Python:为一个奇怪的协议计算文件的校验和

时间:2014-07-18 10:25:32

标签: python

我正在计算类似于文件的校验和以及我想要移植到python的奇怪协议的麻烦。

校验和是一个4字节的无符号整数,它是添加文件的所有4字节无符号整数的结果。例如,假设以下文件(请注意实际文件大约为16MB):

ff fe fd fc fb fa f9 f8  f7 f6 f5 f4 f3 f2 f1 f0
ef ee ed ec eb ea e9 e8  e7 e6

通过我的实现(见下文),计算如下:

0xfffefdfc + 0xfbfaf9f8 + 0xf7f6f5f4 + 0xf3f2f1f0 + 0xefeeedec + 0xebeae9e8 + 0xe7e60000 = 0x6aba3b7ac

但是,它应该是0xaba3b7ac

我试过这样的事情:

import mmap
import struct

# Prepare file
file = open("file.bin", 'rb')
map = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ)

# Calculate checksum
checksum = 0
while (map.tell() < map.size()):
    checksum += struct.unpack('>I', map.read(4))[0]

print "checksum: ", checksum

# Close file.
map.close()
file.close()

但我发现有两个问题。

  1. 首先,输出数量太大。我需要一个4字节的数字。 使用前面的代码,典型测试文件的输出就像 0x165c0458b224ae但它应该类似0xcaac5458(4字节无符号 整数)。
  2. 我的方法很慢。原始代码(用C编写)可以 计算速度要快得多。
  3. 我真的很坚持这一点,所以任何帮助都会非常感激。

    提前致谢,抱歉我的英语不好。


    更新

    Serge Ballesta解决了第一个问题。解决方案是在打印校验和之前添加以下行:

    checksum &= 0xffffffff
    

    但计算仍然很慢。我想有一个快速的解决方案,但我不知道该怎么做。

2 个答案:

答案 0 :(得分:2)

一种方法是使用array模块并将所有四个字节加载到内存中,对它们求和,然后强制回到4字节(正如Serge已经提到的那样)。

import os
from array import array

#with open('data.bin', 'wb') as fout:
#   fout.write(os.urandom(16800000))

with open('data.bin', 'rb') as fin:
    arr = array('L')
    arr.fromfile(fin, 16800000 / 4)
    arr.byteswap()
    checksum = sum(arr) & 0xFFFFFFFF

我的笔记本电脑不到一秒钟......不确定你想要它多快多久......

答案 1 :(得分:1)

我认为你有问题,但不是你描述的问题。

从任意长数字传递到4字节整数就像n4b = n & 0x0FFFFFFFF

一样简单

我不明白为什么计算为Windows机器编写的C源代码无法在Unix机器上编译。

话虽如此,6293623225328814 & 0xFFFFFFFF在hexa中提供14880698060x58b224ae,这不是您预期的结果。我想你有和endianness问题。你应该先用little endian和big endian来计算它,以便知道选择哪个。

# Calculate checksum
checksum_be = 0
checksum_le = 0
while (map.tell() < map.size()):
    checksum_be += struct.unpack('>I', map.read(4))[0]
    checksum_le += struct.unpack('<I', map.read(4))[0]
checksum_be &= 0x0FFFFFFFF
checksum_le &= 0x0FFFFFFFF

print "checksums: ", checksum_be, checksum_le