[英]How to create Uncompressed Zip archive in Java
我正在使用 Java 的 Zip 实用程序 package,想知道如何创建完全没有压缩的 zip 文件。 将级别设置为 0 没有帮助。 这是正确的吗?
此外,当我使用STORED
方法时,它会抛出以下异常:
java.util.zip.ZipException: STORED entry missing size, compressed size, or crc-32
我可以设置大小但现在抛出以下异常:
java.util.zip.ZipException: invalid entry crc-32
我只是通过搜索 web 来关注所有可用的示例,我想我无法真正正确地理解它。 如果有人可以帮助我并向我提供建议以纠正我可能正在做的问题,那就太好了。
我对aperkins解决方案很感兴趣 (自删除以来),但我知道它为何有效。 这条线(后来在他的回答中得到纠正)
zipOut.setLevel(ZipOutputStream.STORED); // accidentally right
使用静态值ZipOutputStream.STORED
,巧合等于0
。 那么该行正在做的是将默认DEFLATED方法使用的级别设置为零压缩(这显然是您想要做的,但碰巧只能靠运气工作)。 因此,要明确安全地获得您想要的内容,请使用以下内容:
zipOut.setMethod(ZipOutputStream.DEFLATED); // this line optional
zipOut.setLevel(0);
要么
zipOut.setLevel(Deflater.NO_COMPRESSION);
如果你使用
zipOut.setMethod(ZipOutputStream.STORED);
zipOut.setLevel(Deflater.NO_COMPRESSION);
你可能会得到Keya在原始问题中提到的异常。 我相信Christian Schlichtherle是对的; 您正在获取例外,因为您没有在条目中设置CRC。 这种影响是要使用STORED方法,你必须首先读取整个条目文件,或者在调用zipOut.putNextEntry()
之前找到一些其他方法来设置大小,压缩大小(必须相等)和CRC 。 否则,如果通过向输出流写入太多字节来超出size属性,则会遇到更多异常。 似乎ZIP规范说如果你正在编写STORED数据,那么它必须在数据本身之前编写标题[包括CRC-32和长度]“,因此需要在它之前设置java API可以启动,因为它基本上只支持流式传输到最终的zip文件。
您需要使用STORED
方法,但这需要您所设置的size
, compressedSize
和crc32
相应的属性ZipEntry
后,才能调用putNextEntry
在ZipOutputStream
。 您可以使用Crc32OutputStream
预先计算CRC-32。
供参考:
在JDK方法的源代码[java.util.zip.ZipOutputStream.setLevel(int)]中:
public void setLevel(int level) {
def.setLevel(level);
}
它只是将压缩级别设置重定向到字段变量[def],这是[java.util.zip.Deflater]的一个实例。
并在类[java.util.zip.Deflater]的源代码中:
/**
* Compression level for no compression.
*/
public static final int NO_COMPRESSION = 0;
/**
* Compression level for fastest compression.
*/
public static final int BEST_SPEED = 1;
/**
* Compression level for best compression.
*/
public static final int BEST_COMPRESSION = 9;
/**
* Default compression level.
*/
public static final int DEFAULT_COMPRESSION = -1;
所以,如果你使用常量值[Deflater.NO_COMPRESSION],我认为它会更具可读性:
zipOut.setMethod(ZipOutputStream.DEFLATED);
zipOut.setLevel(Deflater.NO_COMPRESSION);
public static void zipForStored(String srcFile, String zipFile) throws Exception {
File file = new File(zipFile);
if (!file.exists()) file.createNewFile();
ZipOutputStream outZip = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
outZip.setMethod(ZipOutputStream.STORED);
ZipFiles(srcFile, null, "", outZip);
outZip.finish();
outZip.close();
}
private static void ZipFiles(String folder, FilenameFilter filter, String file, ZipOutputStream zipOutputSteam) throws Exception {
if (zipOutputSteam == null)
return;
File f = new File(folder, file);
if (f.isFile()) {
ZipEntry zipEntry = new ZipEntry(file);
FileInputStream inputStream = new FileInputStream(f);
zipEntry.setSize(f.length());
zipEntry.setCompressedSize(f.length());
zipEntry.setCrc(computeCrc(f));
zipOutputSteam.putNextEntry(zipEntry);
int len;
byte[] buffer = new byte[4096];
while ((len = inputStream.read(buffer)) != -1) {
zipOutputSteam.write(buffer, 0, len);
}
zipOutputSteam.closeEntry();
inputStream.close();
} else {
String fileList[] = f.list(filter);
if (fileList.length <= 0) {
ZipEntry zipEntry = new ZipEntry(file + File.separator);
zipEntry.setSize(0);
zipEntry.setCompressedSize(0);
zipEntry.setCrc(0);
zipOutputSteam.putNextEntry(zipEntry);
zipOutputSteam.closeEntry();
}
for (int i = 0; i < fileList.length; i++) {
if (TextUtils.isEmpty(file)) {
ZipFiles(folder, filter, fileList[i], zipOutputSteam);
} else {
ZipFiles(folder, filter, file + File.separator + fileList[i], zipOutputSteam);
}
}
}
}
/**
* Computes the CRC checksum for the given file.
*
* @param file The file to compute checksum for.
* @return A CRC32 checksum.
* @throws IOException If an I/O error occurs.
*/
private static long computeCrc(File file) throws IOException {
CRC32 crc = new CRC32();
InputStream in = new FileInputStream(file);
try {
byte[] buf = new byte[8192];
int n = in.read(buf);
while (n != -1) {
crc.update(buf, 0, n);
n = in.read(buf);
}
} finally {
in.close();
}
return crc.getValue();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.