为啥我的 java.util.zip 函数显示不一致的行为?

Posted

技术标签:

【中文标题】为啥我的 java.util.zip 函数显示不一致的行为?【英文标题】:Why are my java.util.zip functions showing inconsistent behavior?为什么我的 java.util.zip 函数显示不一致的行为? 【发布时间】:2011-01-28 19:30:36 【问题描述】:

我有一个 Java 应用程序,它使用 java.util.zip 库来压缩和解压缩文件。我所拥有的是服务器上的一个 zip 文件(由我的应用程序创建)和客户端压缩他的一些文件并将文件上传到服务器,但如果底层文件没有区别,那么我不想浪费时间上传。我想我可以计算客户端和服务器端的 MD5 哈希值,看看它们是否相同,但发生的是我使用我的应用程序解压缩一个 zip 文件,然后不更改任何底层文件,我使用我的应用程序重新压缩它,但是新旧 zip 文件具有不同的 MD5 哈希值。有谁知道为什么会这样,以及是否有更好的方法来比较两个 zip 文件?谢谢。

【问题讨论】:

【参考方案1】:

我认为情况更糟:

两次执行相同的压缩操作会产生两个不同的压缩存档:

> zip some.zip some.txt 
  adding: some.txt (stored 0%)
> zip other.zip some.txt
  adding: some.txt (stored 0%)
> ll
total 24
-rw-r--r--  1 cthies  staff  170 12 Dez 18:01 other.zip
-rw-r--r--  1 cthies  staff    4 12 Dez 18:01 some.txt
-rw-r--r--  1 cthies  staff  170 12 Dez 18:01 some.zip
> md5 *.zip
MD5 (other.zip) = f56d7753c5af78427274d930b9fb8c90
MD5 (some.zip) = e2f0382c4ad31871f62fb559157df8e8

查看二进制文件,我们只能在一处看到差异:

> xxd some.zip > some.xxd
> xxd other.zip > other.xxd
> colordiff *.xxd
3c3
< 0000020: 6d65 2e74 7874 5554 0900 0363 33e6 4e78  me.txtUT...c3.Nx
---
> 0000020: 6d65 2e74 7874 5554 0900 0363 33e6 4e64  me.txtUT...c3.Nd

我认为(取决于 zip-app 本身)当前系统时间可以/将会涉及。因此,任何 zip 操作 - 在完全相同的来源上 - 都可以(!)是唯一的,因此不能假定校验和相等。

我发现的与时间无关的工具:tar7z。 (都是命令行) IE。 tar7z 以相等的校验和 (md5) 复制档案。

(在 OSX 10.6.8 上使用命令行 zip 实用程序测试)

【讨论】:

【参考方案2】:

1) 检查文件上的时间戳。解压后的文件可能有不同的最后修改日期和/或创建日期。该文件元数据可能用于创建哈希。

2) 您是否在两个系统上使用相同的操作系统?如果操作系统不同,它们可能使用不同的字符编码。

3) 你能区分 zip 文件吗?不同的 MD5 哈希值应该意味着不同的数据。这会很混乱,但您可能会通过比较原始文件获得一些线索。

【讨论】:

【参考方案3】:

只是在黑暗中的狂野射击 - 您计算哈希值的两个文件系统是不同大小写的吗?

也就是说,是 Windows 之一,它将 ABC.CLASS 和 abc.class 文件名视为相同,而 Unix 变体之一将 ABC.CLASS 和 abc.class 视为不同?

只是一个疯狂的猜测......

编辑:您还可以查看嵌入的目录分隔符 / \ 。或:在 zip 文件中。

【讨论】:

也可能是更改的文件时间戳。【参考方案4】:

您无法比较不同 zip 程序生成的 zip 文件并期望它们完全相同,即使压缩前使用了完全相同的文件。

不保证压缩文件在两种不同的 zip 编码实现之间是确定性的。 Zip 的工作原理是用相当于查找键的内容替换重复的数据部分。两种不同的算法可以不同地确定字典(重复数据集),以优化压缩级别。然而,这两种实现都可以创建有效的 zip 文件,当解压缩时会生成相同的文件。

唯一可靠的方法是确保在两种情况下使用完全相同的 zip 算法。

编辑:这就是为什么您在 Deflate 算法的 Java 实现中看到不同的压缩级别设置http://download.oracle.com/javase/1.5.0/docs/api/java/util/zip/Deflater.html

【讨论】:

确实,相同的算法,相同的选项和容差设置。 没错!我也应该提到这一点。 OP 说他们在进程的两端都使用 java.util.zip。除了在一些非常不寻常的情况下,这意味着压缩算法将是相同的,由 Sun^h^h^h Oracle 提供。 @Joe Zitzelberger - 我不是这么读的。也许OP可以澄清。他特别指出他有一个由他的应用程序创建的服务器端 zip 文件,但他将其与说客户端创建一个 zip 分开。他没有指定客户端必须使用完全相同的算法和设置。

以上是关于为啥我的 java.util.zip 函数显示不一致的行为?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 java.util.zip.CRC32.getValue() 返回一个 long 而不是 int?

Java.util.zip 替换单个 zip 文件

如何解决 java.util.zip.ZipException?

我的Android进阶之旅------&gt;Android编译错误java.util.zip.ZipException: duplicate entry的解决方法

java.util.zip.ZipException: invalid LOC header (bad signature)

javazip压缩包过大解压失败