6

我正在编写一个 Python 程序来从 6 GB bz2 文件的中间提取数据。bzip2 文件由可独立解密的数据块组成,因此我只需要找到一个块(它们由魔术位分隔),然后在内存中从中创建一个临时的单块 bzip2 文件,最后将其传递给bz2.decompress 函数。容易,不是吗?

bzip2格式的末尾有一个文件的 crc32 校验和。没问题,binascii.crc32 来救援。可是等等。要校验和的数据不一定以字节边界结束,crc32 函数对整数字节进行操作。

我的计划:在除最后一个字节之外的所有字节上使用 binascii.crc32 函数,然后使用我自己的函数用最后 1-7 位更新计算出的 crc。但是几个小时的编码和测试让我一头雾水,我的疑惑可以归结为这个问题:crc32("\x00") 怎么不是0x00000000?根据维基百科的文章,不应该吗?

您从 0b00000000 开始并用 32 个 0 填充,然后用 0x04C11DB7 进行多项式除法,直到前 8 位中没有剩余,即立即。您的最后 32 位是校验和,怎么可能不全为零?

我在 Google 上搜索了答案并查看了几个 CRC-32 实现的代码,但没有找到任何线索说明为什么会这样。

4

2 回答 2

10

为什么 crc32("\x00") 不是 0x00000000?

基本的 CRC 算法是将输入消息视为 GF(2) 中的多项式,除以固定的 CRC 多项式,并使用多项式余数作为结果哈希。

CRC-32 对基本算法进行了一些修改:

  1. 消息的每个字节中的位被反转。例如,字节 0x01 被视为多项式 x^7,而不是多项式 x^0。
  2. 该消息在右侧填充了 32 个零。
  3. 此反向和填充消息的前 4 个字节与 0xFFFFFFFF 进行异或运算。
  4. 取反余数多项式。
  5. 余数多项式与 0xFFFFFFFF 进行异或运算。
  6. 回想一下,CRC-32 多项式的非反转形式是 0x104C11DB7。

让我们计算一字节字符串 0x00 的 CRC-32:

  1. 消息:0x00
  2. 反转:0x00
  3. 填充:0x00 00 00 00 00
  4. 异或:0xFF FF FF FF 00
  5. 除以 0x104C11DB7 时的余数:0x4E 08 BF B4
  6. 异或:0xB1 F7 40 4B
  7. 反转:0xD2 02 EF 8D

就是这样:0x00 的 CRC-32 是 0xD202EF8D。
(您应该验证这一点。)

于 2011-07-12T23:08:47.977 回答
2

除了 one-shotdecompress函数之外,bz2 模块还包含一个BZ2Decompressor在将数据馈送到 decompress 方法时解压缩数据的类。因此,它不关心文件结束校验和,并在到达块末尾时提供所需的数据。

为了说明,假设我已经找到了我希望从文件中提取的块并将其存储在bitarray.bitarray实例中(其他位旋转模块可能也可以工作)。然后这个函数将解码它:

def bunzip2_block(block):
    from bz2 import BZ2Decompressor
    from bitarray import bitarray

    dummy_file = bitarray(endian="big")
    dummy_file.frombytes("BZh9")
    dummy_file += block

    decompressor = BZ2Decompressor()
    return decompressor.decompress(dummy_file.tobytes())

请注意,bitarray 的frombytestobytes方法以前被称为fromstringand tostring

于 2011-02-19T23:21:14.487 回答