使用缓冲区计算 Python 中二进制文件的 CRC / CRC32 哈希/校验和

Calculate a CRC / CRC32 hash / checksum on a binary file in Python using a buffer

我一直在努力自学 Python 所以我并不完全理解我在做什么。我不好意思这么说,但我的问题应该很容易回答。我希望能够使用类似于以下的代码对二进制文件执行 CRC 校验和:

# http://upload.wikimedia.org/wikipedia/commons/7/72/Pleiades_Spitzer_big.jpg

import zlib

buffersize = 65536

with open('Pleiades_Spitzer_big.jpg', 'rb') as afile:
    buffr = afile.read(buffersize)
    while len(buffr) > 0:
        crcvalue = zlib.crc32(buffr)
        buffr = afile.read(buffersize)

print(format(crcvalue & 0xFFFFFFFF, '08x'))

正确的结果应该是 "a509ae4b" 但我的代码的结果是 "dedf5161"。我认为正在发生的事情是在文件的第一个或最后一个 64kb 而不是整个文件上计算校验和。

应该如何更改代码以便在不将整个文件加载到内存的情况下检查整个文件?

照原样,代码 "works" 在 Python 2.x 或 3.x 中。如果代码 必须 在一个或另一个中,我希望它在 3.x.

您目前只计算文件最后一块的 CRC。为了将此传递电流 crcvalue 固定为 crc32 作为起始值:

import zlib

buffersize = 65536

with open('Pleiades_Spitzer_big.jpg', 'rb') as afile:
    buffr = afile.read(buffersize)
    crcvalue = 0
    while len(buffr) > 0:
        crcvalue = zlib.crc32(buffr, crcvalue)
        buffr = afile.read(buffersize)

print(format(crcvalue & 0xFFFFFFFF, '08x')) # a509ae4b

这是来自 Python 文档的相关部分:

If value is present, it is used as the starting value of the checksum; otherwise, a default value of 0 is used. Passing in value allows computing a running checksum over the concatenation of several inputs.

虽然@niemmi 接受的 非常出色且准确,但这里是 Python 3.8+ 兼容解决方案,有助于稍微简化代码。


Python 3.8+

下面的示例使用 walrus assignment operator ( := ) 来跟踪正在读取的块:

import zlib

size = 1024*1024*10  # 10 MiB chunks
with open('/tmp/test.txt', 'rb') as f:
    crcval = 0
    while chunk := f.read(size):
        crcval = zlib.crc32(chunk, crcval)

print(f'{crcval & 0xFFFFFFFF:08x}')

测试

echo "Some boring example text in a file." > /tmp/test.txt

$ crc32 /tmp/test.txt
2a30366b

使用上面示例代码的校验和值:

2a30e66b