为啥我的 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 操作 - 在完全相同的来源上 - 都可以(!)是唯一的,因此不能假定校验和相等。
我发现的与时间无关的工具:tar、7z。 (都是命令行) IE。 tar 和 7z 以相等的校验和 (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.ZipException?
我的Android进阶之旅------>Android编译错误java.util.zip.ZipException: duplicate entry的解决方法
java.util.zip.ZipException: invalid LOC header (bad signature)