我知道,谁会想用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的说明,请参见答案:
-
孙氏
ZipFile.entries()
总是按它们在文件中出现的顺序返回zipEntries,而apache commons
ZipFile.getEntries()
以随机顺序返回条目。这导致了一个有趣的错误,因为一些代码假设条目是“有序的”。