我在通过zip4j
生成ZIP文件时遇到问题。
我可以使用以下代码生成ZIP存档(我省略了一些与问题无关的部分),这基本上取自zip4j
教程:
File zipFile = new File(zipName);
ZipParameters params = new ZipParameters();
params.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
params.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
byte[] buffer = new byte[8192];
try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile))) {
for (/* loop through list of input data */) {
String outputName = /* method to determine file name */;
try (InputStream in = /* method to get IS */ ) {
params.setFileNameInZip(outputName);
File tmpEntry = new File(outputName);
tmpEntry.createNewFile();
out.putNextEntry(tmpEntry, params);
int len;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
tmpEntry.delete();
out.closeEntry();
in.close();
}
}
}
问题是虽然所有文件都正确地包含在ZIP存档中,但是它们声明的文件大小为0.我可以使用" dumb"解压缩它们。 ZIP阅读器(如内置的TotalCommander'),因为所有数据实际上都在这里,但更多"聪明"程序(如7zip)产生CRC错误并拒绝将它们打开为损坏。
我会说我需要以某种方式声明文件大小(我绝对不会在我的代码片段中这样做),但我无法找到(可能很明显的)解决方案。我用谷歌搜索了原住民java.util.zip.ZipEntry
有.setSize()
方法,但我在zip4j
中看不到这样的内容......
任何人都知道正确的方法吗?
答案 0 :(得分:1)
所以解决方案非常简单。只需将以下设置添加到ZipParameters
:
params.setSourceExternalStream(true);
我是如何找到的?
我深入研究了代码,并在closeEntry()
CipherOutputStream.java
类的zip4j
方法中找到了以下内容:
if (zipParameters.isSourceExternalStream()) {
fileHeader.setUncompressedSize(totalBytesRead);
if (localFileHeader.getUncompressedSize() != totalBytesRead) {
localFileHeader.setUncompressedSize(totalBytesRead);
}
}
这是唯一一个setUncompressedSize()
- 听起来与声明的文件大小有关的地方 - 调用方法。所以我怀疑并尝试在我的代码中设置参数。它完成了这项工作。
所吸取的教训是this example使用zip4j
是不正确的,因为它缺少重要的代码行。