1

下面是一些从仅包含单个文件的 zip 文件中提取文件的代码。但是,提取的文件与通过 WinZip 或其他 zip 实用程序提取的相同文件不匹配。如果文件包含奇数个字节,我希望它可能会关闭一个字节(因为我的缓冲区大小为 2,一旦读取失败,我就会中止)。但是,在分析(使用 WinMerge 或 Diff)以下代码提取的文件与通过 Winzip 提取的文件时,Java 提取中存在多个字节丢失的区域。有谁知道为什么或如何解决这个问题?

package zipinputtest;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.ZipInputStream;

public class test2 {
    public static void main(String[] args) {
        try {
            ZipInputStream zis = new ZipInputStream(new FileInputStream("C:\\temp\\sample3.zip"));
            File outputfile = new File("C:\\temp\\sample3.bin");
            OutputStream os = new BufferedOutputStream(new FileOutputStream(outputfile));
            byte[] buffer2 = new byte[2];
            zis.getNextEntry();
            while(true) {
                if(zis.read(buffer2) != -1) {
                    os.write(buffer2);
                }
                else break;
            }
            os.flush();
            os.close();
            zis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

我能够使用此图像产生错误(将其保存并压缩为 sample3.zip 并在其上运行代码),但任何足够大小的二进制文件都应显示差异。

在此处输入图像描述

4

2 回答 2

2

您可以使用更逐字的方式来检查是否所有字节都被读取和写入,例如像这样的方法

  public int extract(ZipInputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[BUFFER_SIZE];
    int total = 0;
    int read;
    while ((read = in.read(buffer)) != -1) {
      total += read;
      out.write(buffer, 0, read);
    }
    return total;
  }

如果在read中未使用参数write(),则该方法假定将写出 的全部内容,如果未完全填写buffer,则可能不正确。buffer

OutputStream可以在方法内部或外部冲洗和关闭extract()。调用close()应该就足够了,因为它也调用flush().

在任何情况下,Java 的“标准”I/O 代码,就像java.util.zip包一样,已经过测试和广泛使用,所以它不太可能有一个根本性的错误,导致字节如此容易丢失。

于 2017-04-20T01:39:32.883 回答
2
while (true) {
    if(zis.read(buffer2) != -1) {
        os.write(buffer2);
    }
    else break;
}

常见问题。你忽略了计数。应该:

int count;
while ((count = zis.read(buffer2)) != -1)
{
    os.write(buffer2, 0, count);
}

注意:

  1. 缓冲区大小为 2 是荒谬的。使用 8192 或更多。
  2. flush()之前close()是多余的。
于 2017-04-20T02:01:25.237 回答