如何将二进制文件缓冲区解压缩为两个变量?

How to unpack a binary file buffer into two variables?

我有一个包含 4 字节二进制值的二进制文件,每个二进制值代表一组两个 short int。我知道我可以将单个 4 字节二进制值解压缩为两个短整数,如下所示:

from struct import unpack

fval = b'\xba\x1e\x99\x01' #actualy read from some file
qualdip, azi = unpack('hh', fval)
print(type(qualdip), qualdip)
print(type(azi), azi)

>>> <class 'int'> 7866
>>> <class 'int'> 409

现在,我想解压缩整个缓冲区。目前我在做:

qualdips = []
azis = []
with open(bfile, 'rb') as buf:
    fval = buf.read(4)
    while fval:
        qualdip, azi = unpack('hh', fval)
        azis.append(azi)
        qualdips.append(qualdip)
        fval = buf.read(4)

对于一个 277MB 的文件,这需要一分钟多的时间,而且似乎会产生巨大的内存开销。

我想将整个文件缓冲区直接解压到两个变量中。我该如何实现?

我怀疑struct.unpack_from是我的朋友,但我不确定如何制定格式。

with open(bfile, 'rb') as buf:
    qualdip, azi = unpack_from('hh', buf)

只提取两个值,并且(我知道我的文件的元素数量)

with open(bfile, 'rb') as buf:
    qualdip, azi = unpack_from('72457091h72457091h', buf)

期望如此多的输出变量。所以:

如何将整个文件缓冲区直接解压到两个变量中?

我不知道如何将值直接解压缩到两个列表中,但您可以将整个文件解压缩到一个元组中,然后将其分成两部分:

fval = b'\xba\x1e\x99\x01' * 3
unpacked= unpack('3h3h', fval)
qualdip = unpacked[0::2]
azi = unpacked[1::2]

或者,使用 islice to create an iterator,这将减少内存消耗。

qualdip = islice(unpacked, 0, None, 2)
azi = islice(unpacked, 1, None, 2)

我认为这可能是一种更快的方法:

import os
import struct

def pairwise(iterable):
    "s -> (s0,s1), (s2,s3), (s4, s5), ..."
    a = iter(iterable)
    return zip(a, a)

bfile = 'bfile.bin'
filesize = os.stat(bfile).st_size
numvals = filesize // 2

with open(bfile, 'rb') as bf:
    fmt = '{}h'.format(numvals)
    values = struct.unpack(fmt, str(bf.read()))

qualdips, azis = zip(*pairwise(values))