在不使用ZipFile的情况下随机访问压缩文件(因为ZipFile有一个主要错误)

时间:2009-07-22 16:32:17

标签: java compression zipfile zipinputstream

我知道,我知道,谁想要在java中压缩或解压缩大文件。完全不合理。目前暂停怀疑,并假设我有一个很好的理由解压缩大型zip文件。

问题1:ZipFile有一个bug (bug # 6280693),sun已在java 1.6(Mustang)中修复此问题。由于我们的软件需要支持java 1.4,因此修复程序没有用。据我所知,这个bug就像这样。运行以下代码时,Java会分配一大块足以容纳整个文件的内存。

ZipFile zipFile = new ZipFile("/tmp/myFile.zip");

如果/tmp/myFile.zip是4gb,则java分配4gb。这会导致堆异常。遗憾的是,堆大小为+ 4gb不是可接受的解决方案。 =(

问题1的解决方案:使用ZipInputStream,将文件作为流处理,从而减少和控制内存占用。

byte[] buf = new byte[1024];
FileInputStream fs = new FileInputStream("/tmp/myFile.zip")
ZipInputStream zipIn = new ZipInputStream(fs);

ZipEntry ze = zipIn.getNextEntry();

while (ze != null){
  while ((int cr = zipIn.read(buf, 0, 1024)) > -1) 
    System.out.write(buf, 0, len);
  ze = zipIn.getNextEntry();
}

问题2:我想随机访问ZipEntries。也就是说,我想只解压缩一个ZipEntry,而不必搜索整个流。目前我正在构建一个zipEntries列表,名为zes:

        ZipInputStream zin = new ZipInputStream("/tmp/myFile.zip");

        ZipEntry ze = zin.getNextEntry();
        List<ZipEntry> zes = new ArrayList<ZipEntry>();

        while(ze!=null){
            zes.add(ze);
            ze = zin.getNextEntry();
        }

然后,当我需要解压缩特定的zipEntry时,我会遍历所有的zipEntries,直到找到匹配的zipEntry,然后我解压缩。

        ZipEntry ze = in.getNextEntry();
        while (! ze.getName().equals(queryZe.getName())){
            ze = zin.getNextEntry();
        }

        int cr;

        while ((cr = zin.read(buf)) > -1) 
            System.out.write(buf, 0, cr);

Quertion:ZipFile可以随机访问ZipEntries。

new BufferedInputStream(zipFile.getInputStream(zipEntry));

如何在不使用ZipFile的情况下获得相同的能力?

请注意,ZipInputStream有一些strange behavior

关于java和ZipFiles的特别好的文档可以在这里找到:

http://commons.apache.org/compress/zip.html

关于切换替换sun ZipFile的注释与apache commons ZipFile的答案建议:

  1. Sun的ZipFile.entries()总是按照它们在文件中出现的顺序返回ZipEntries,而apache commons ZipFile.getEntries()以随机顺序返回条目。这引起了一个有趣的错误,因为有些代码假设条目是“按顺序”。

2 个答案:

答案 0 :(得分:4)

对于此任务,您可能需要查看Apache Commons CompressApache Commons VFSTrueZip。所有这些都应该与Java 1.4兼容,并且可能支持您需要的功能。

答案 1 :(得分:2)

你可以看看Apache Commons Compress,它适用于1.4+,但我不知道它是否暴露了同样的错误。