java 为什么MD5哈希值是不同的两个Excel文件看起来相同

nnsrf1az  于 2023-02-07  发布在  Java
关注(0)|答案(4)|浏览(410)

我有两个excel文件保存在不同的位置。一个是直接从浏览器下载的,另一个是使用 selenium 驱动程序下载的。我手动检查了这两个文件,两者是完全相同的。但为两个文件生成的MD5哈希值是不同的。如何解决这个问题。

bxgwgixi

bxgwgixi1#

MD5是一个散列函数。人们使用散列函数来验证文件、流或其他资源的完整性。当谈到散列函数时,当你验证文件的完整性时,你是在验证在位级别上,文件是相同的。
这样做的结果是,当您在逐位级别上比较具有完整性约束的文件时,哈希函数可以完美地工作。
然而,考虑到Excel电子表格的本质,如果在逐位级别上向文档添加、删除或移动一位,那么该文件的哈希值将完全不同(并非总是如此,但不必担心)。
由于Excel的驱动程序与selenium使用的驱动程序有很大的不同,特别是selenium可能对文件进行压缩和其他更改/优化,因此,当然,散列也会有所不同。
我的建议:第一步:调出diff中的文件,找出这两个文件之间的不同之处,如果两个文件的哈希值不同,那么这两个文件也不同,这几乎是不言自明的。
第二:编写一个驱动程序来比较这些电子表格中的信息,以验证文档的完整性(您可以获取这些信息的哈希值),而不是在逐位级别上验证文件。
我建议将两者都导出为CSV,然后逐行比较。

soat7uwm

soat7uwm2#

MD5算法对文件进行完整的计算,包括存储在文件中的元数据(文件名、日期等),因此两个文件可以在“主要内容”上相同,但在某些字节上不同。
可能很难确定文件的哪一部分是MD5检查真正感兴趣的。
如果您使用Windows,并且只对Excel文件感兴趣,请尝试使用此类工具:http://www.formulasoft.com/download.html

jv4diomz

jv4diomz3#

你确定元数据包含在散列中吗?对此做一些研究是明智的。
如果这是真的,你将永远不会找到匹配的哈希,因为时间戳匹配的可能性将非常低,你也可以改变文件名一千次,哈希将是相同的。此外,当一个反病毒扫描一个文件,它会改变访问的时间戳属性,你的哈希将不断变化,如果元数据包括在一台机器上的哈希,这是不断被反病毒扫描。

x759pob2

x759pob24#

老帖子,新视角:
TL;DR -zip规范包括时间戳。请参阅:zip上的维基百科条目。下面的序列将回答问题“我的两个电子表格实际上包含相同的数据吗?”

unzip file1.xlsx -d dir1/
unzip file2.xlsx -d dir2/
diff -rq dir1/ dir2/

如果最后的diff命令是空的,那么您的电子表格是相同的,尽管两个不同文件的散列不同。
alvonellos给出的公认答案是正确的。MD5散列几乎可以肯定会为任何方式不同的文件给予不同的结果,即使是一个位。在最初问题提出后的10年里,MD5散列已经被弃用,取而代之的是加密更安全的散列,但是它们通常仍然适合OP的用例--验证本地文件系统上的文件。意外冲突的概率是几亿分之一,具体取决于输入。重要的是,非常相似但不完全相同的文件更有可能具有不同的哈希值。换句话说,制作两个具有相同哈希值的文件实际上很难做到,需要在其中一个文件的许多地方进行非常具体的更改。如果您不信任MD5,您可以使用任何风格的SHA或其他散列算法,您将得到类似的结果。
深入了解.XLSX:
.xlsx实际上是.zip格式,可以使用linux unzip工具来解压缩.xlsx:

unzip file.xlsx -d dir/

前面的回答建议对这两个文件计算diff,但没有描述最好的方法,一旦你对.xlsx文件使用了unzip,你就有了一个目录结构,里面有电子表格的“核心”:

dir/
    [Content_Types].xml
    _rels/
          .rels
    xl/
          workbook.xml
          worksheets/
                      sheet1.xml
                      sheet2.xml
                      sheet3.xml
 . . .

一旦你完成了这两个不同的电子表格,比如file1.xlsx扩展到dir1/file2.xlsx扩展到dir2/,你可以对这两个文件做递归比较:

diff -rq dir1/ dir2/ # <-- The -rq flags mean recursive, file-name-only

注意,如果你真正想知道的是两个文件是否有不同的 * 内容 *,那么这个命令会回答这个问题。如果这个命令没有输出,那么目录之间的内容没有区别。也就是说,两个原始电子表格的内容没有区别。
如果您对.xlsx文件本身的差异感兴趣,可以使用linux xxd实用程序深入了解文件头的一些细节:

xxd file1.xlsx | head -n1 # <-- look at the first line (16 bytes)
00000000: 504b 0304 1400 0000 0800 acab a354 7d3d  PK...........T}=

xxd file2.xlsx | head -n1
00000000: 504b 0304 1400 0000 0800 66ac a354 7d3d  PK........f..T}=

时间戳显示在第六个二进制八位数中(在本例中,分别为acab66ac)。日期显示在第七个二进制八位数中(在本例中,两者均为a354)。
请记住,比.XLSX文件只是一个.ZIP文件与一组目录和文件,遵循微软的标准压缩在它里面。每一个包含的文件将有自己的CRC-32哈希。
第八个和第九个八位字节包含CRC-32散列,该散列由生成文件的任何zip实用程序生成。因此,如果您手边有xxd实用程序,则可以跳过上面提到的所有解压缩步骤,只需执行以下操作:

xxd -s 14 -l 4 file1.xlsx
xxd -s 14 -l 4 file2.xlsx

输出如下所示:

xxd -s 14 -l 4 file1.xlsx
0000000e: 7d3d 6d31                                }=m1

xxd -s 14 -l 4 file2.xlsx
0000000e: 7d3d 6d31                                }=m1

从而确认两个内部文件具有相同的哈希(不管时间戳)。2这是一个方便的检查包含在.ZIP(即.XLSX)中的第一个文件。
要全面查看.XLSX存档中包含的所有文件内容的CRC 32哈希值,您可以使用以下算法(伪代码):

bytes := "504b0102" as binary

chunks_array := file_content split on bytes

crc32_hashes = []

crc32_hashes := 
  for each chunk in chunks_array starting at 1: // skip index 0
    append substring(24, 8) of hex(chunk)  // 24 / 2 = 12 + 4 = offset 16

顶部的幻数504b0102是.ZIP文件末尾的文件摘要的分隔符,翻转为字节序。
得到的crc32_hashes数组包含其中每个文件的CRC-32散列值。同样,由于内部XML中的内部时间戳机制和其他特定于实现的元数据,电子表格的可读部分可能相同,但CRC-32散列值不同。
然而,这是一种获取两个Excel文件“指纹”的廉价方法,可以确定它们是否是完全相同的. XLSX文件的两个副本。它只是字符串操作,比重新散列要少得多的时间和处理器密集度。它依赖于在创建.XLSX文件时已经完成的散列。

相关问题