如何在 Java 中创建未压缩的 Zip 存档

Posted

技术标签:

【中文标题】如何在 Java 中创建未压缩的 Zip 存档【英文标题】:How to create Uncompressed Zip archive in Java 【发布时间】:2010-11-15 11:19:15 【问题描述】:

我正在使用 Java 的 Zip 实用程序包,想知道如何创建一个完全不压缩的 zip 文件。将级别设置为 0 无济于事。是这样吗?

另外,当我使用STORED 方法时,它会抛出以下异常:

java.util.zip.ZipException: STORED entry missing size, compressed size, or crc-32

我可以设置大小,但现在抛出以下异常:

java.util.zip.ZipException: invalid entry crc-32 

我只是在网上搜索所有可用的示例,我猜我无法真正正确理解它。如果有人能在这方面帮助我并提供建议来纠正我可能正在做的问题,那就太好了。

【问题讨论】:

那些 int 常量是来自另一个时代(可能是 C)的“代码重音”......我希望 David Connelly 在编写 ZipOutputStream 之前已经阅读过 Java 枚举。 @ChristopheRoussy 那会相当困难,因为ZipOutputStream 出现在枚举之前很多年。 我想知道枚举有什么好。以及 const 整数有什么不酷的地方。 【参考方案1】:

我对 aperkins 解决方案持怀疑态度(已删除),但我知道它为什么有效。该行(此后已在他的回答中更正)

zipOut.setLevel(ZipOutputStream.STORED); // accidentally right

使用的是静态值ZipOutputStream.STORED,恰好等于0。因此,该行所做的是将默认 DEFLATED 方法使用的 level 设置为零压缩(这显然是您想要做的,但碰巧只能靠运气工作)。因此,要明确安全地获得您想要的东西,请改用它:

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文件。

【讨论】:

DEFLATED + Level(0) 导致我的情况是......每个压缩文件(一点)比源文件大:O 我很确定 DEFLATED-0 与 STORE 不同:/ DEFLATED-0 和 STORE 可能不同,但它们具有相同的目标 - 包含未压缩数据的 zip 文件。我不希望任何一种方法都会输出与源文件大小相等的文件。然而,在问题中,Keya 在使用 STORE 方法时遇到了问题,因为获取所需参数需要进行预处理。如果您想要一个小于源文件的压缩文件,请在 setLevel() 中使用不同的值 - 但这不是问题所要求的。 您的代码对我来说失败了。 zip 文件永远不会完成。这么多没有被压缩。【参考方案2】:

仅供参考:

在方法[java.util.zip.ZipOutputStream.setLevel(int)]的JDK源码中:

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);

【讨论】:

【参考方案3】:

您需要使用STORED方法,但这需要您设置对应ZipEntrysizecompressedSizecrc32属性,然后才能在ZipOutputStream上调用putNextEntry .您可以使用 Crc32OutputStream 预先计算 CRC-32。

【讨论】:

谢谢,您似乎是正确的,但是有任何记录吗? 在pkware.com/documents/casestudies/APPNOTE.TXT 的 ZIP 文件格式规范中指定。 @AlexWien 如果您不这样做,ZipOutputStream 将引发错误......幸运的是它收到了一个很好的错误消息。

以上是关于如何在 Java 中创建未压缩的 Zip 存档的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Java(apache 压缩)在 Windows 中创建“有效”的 unix TAR 存档?

如何创建目录的 zip 存档?

在 C++ 中创建一个 zip 存档

如何在不解压缩的情况下列出 zip 存档中的文件?

如何在 Perl 中创建 Zip 存档?

如何像docker一样在linux中创建未命名的网络名称空间?