代码之家  ›  专栏  ›  技术社区  ›  Ethan Heilman

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

  •  2
  • Ethan Heilman  · 技术社区  · 17 年前

    我知道,谁会想用Java压缩或解压缩大文件。完全不合理。暂时暂停怀疑,并假设我有一个很好的理由来解压缩一个大的zip文件。

    问题1: ZipFile 有一个 bug (bug # 6280693) ,Sun已经在Java 1.6(野马)中修复了这个问题。因为我们的软件需要支持Java 1.4,所以修复并不是没有帮助的。据我所知,这个bug是这样工作的。当运行下面的代码时,Java分配足够大的内存块来保存整个文件。

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

    如果/tMP/MyFiel.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,而不必搜索整个流。目前我正在建立一个名为zes的zipEntries列表:

            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时,我会迭代所有的zipEntry,直到找到匹配的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);
    

    查询:zipfile能够随机访问zipEntries。

    new BufferedInputStream(zipFile.getInputStream(zipEntry));
    

    如果不使用zipfile,我怎样才能获得同样的能力?

    请注意,zipinputstream有一些 strange behavior .

    这里可以找到关于Java和ZIPFrice的特别好的文档:

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

    有关将sun-zipfile替换为apache commons-zipfile的说明,请参见答案:

    1. 孙氏 ZipFile.entries() 总是按它们在文件中出现的顺序返回zipEntries,而apache commons ZipFile.getEntries() 以随机顺序返回条目。这导致了一个有趣的错误,因为一些代码假设条目是“有序的”。
    2 回复  |  直到 17 年前
        1
  •  4
  •   toluju    17 年前

    对于此任务,您可能需要查看 Apache Commons Compress , Apache Commons VFS TrueZip . 所有这些都应该是Java 1.4兼容的,并且可能支持您需要的特性。

        2
  •  2
  •   Yishai    17 年前

    你可以看看 Apache Commons Compress ,它与1.4+一起工作,但我不知道它是否暴露在引擎盖下的同一个bug。

    推荐文章