【发布时间】:2018-03-23 08:01:33
【问题描述】:
我有一个巨大的二进制文件(几 GB),其数据格式如下:
4 个后续字节形成一个复合数据点(32 位),其中包括:
b0-b3 4 flag bits
b4-b17 14 bit signed integer
b18-b32 14 bit signed integer
我需要分别访问有符号整数和标志位,并附加到一个列表或一些更智能的数据结构(尚未决定)。目前我正在使用以下代码来读取它:
from collections import namedtuple
DataPackage = namedtuple('DataPackage', ['ie', 'if1', 'if2', 'if3', 'quad2', 'quad1'])
def _unpack_integer(bits):
value = int(bits, 2)
if bits[0] == '1':
value -= (1 << len(bits))
return value
def unpack(data):
bits = ''.join(['{0:08b}'.format(b) for b in bytearray(data)])
flags = [bool(bits[i]) for i in range(4)]
quad2 = _unpack_integer(bits[4:18])
quad1 = _unpack_integer(bits[18:])
return DataPackage(flags[0], flags[1], flags[2], flags[3], quad2, quad1)
def read_file(filename, datapoints=None):
data = []
i = 0
with open(filename, 'rb') as fh:
value = fh.read(4)
while value:
dp = unpack(value)
data.append(dp)
value = fh.read(4)
i += 1
if i % 10000 == 0:
print('Read: %d kB' % (float(i) * 4.0 / 1000.0))
if datapoints:
if i == datapoints:
break
return data
if __name__ == '__main__':
data = read_heterodyne_file('test.dat')
此代码有效,但对我来说太慢了(100k 数据点需要 2 秒,每个 4 字节)。我至少需要 10 倍的速度。
分析器说代码大部分时间花在字符串格式化(获取位)和 _unpack_integer() 中。
很遗憾,我不知道如何继续。我正在考虑使用 cython 或直接编写一些 c 代码来进行读入。我还尝试了 Pypy ant,它给了我巨大的性能提升,但不幸的是,它需要与一个不适用于 Pypy 的更大项目兼容。
【问题讨论】:
-
删除格式并直接在读取值上使用掩码。跳过“转换为字符串以获取位”阶段。
-
谢谢。好吧,这似乎很有意义。所以要得到 i.e.quad2 我需要按照 data &= 00001111111111111100000000000000 做一些事情,但是我不知道如何将其转换为 int16
-
为了严谨起见,1 kB 有 1024 B(不是 1000)。
-
如果我正确理解en.wikipedia.org/wiki/Kibibyte,我想我不同意。
-
对,我总是忘记“i”。
标签: python performance binary