如何在Python中分块循环遍历二进制文件

问题描述 投票:0回答:4

我正在尝试使用 Python 循环遍历一个充满 8 字节记录的长二进制文件。

每条记录的格式为

[ uint16 | uint16 | uint32 ]

(结构格式中的
"HHI"

显然每个 8 字节块都被视为

int
,而不是 8 字节数组,然后导致
struct.unpack
调用失败

with open(fname, "rb") as f:
    sz=struct.calcsize("HHI")
    print(sz)                # This shows 8, as expected 
    for raw in f.read(sz):   # Expect this should read 8 bytes into raw
        print(type(raw))     # This says raw is an 'int', not a byte-array
        record=struct.unpack("HHI", raw ) # "TypeError: a bytes-like object is required, not 'int'"
        print(record)

如何将我的文件作为一系列结构读取,并将它们分别打印出来?

python binary-data
4个回答
4
投票

内置的 iter,如果传递了一个可调用对象和一个哨兵值,将重复调用该可调用对象,直到返回哨兵值。

因此,您可以使用 functools.partial (或使用

lambda
)创建一个部分函数并将其传递给
iter
,如下所示:

with open('foo.bin', 'rb') as f:
    chunker = functools.partial(f.read, 8)
    for chunk in iter(chunker, b''):      # Read 8 byte chunks until empty byte returned
        # Do stuff with chunk

3
投票

f.read(len)
仅返回字节字符串。那么
raw
将是一个字节。

正确的循环方式是:

with open(fname, 'rb') as f:
    while True:
        raw = f.read(8)
        if len(raw)!=8:
            break # ignore the incomplete "record" if any
        record = struct.unpack("HHI", raw )
        print(record)

0
投票

我以前从未使用过这个,但它看起来像是一个初始化问题:

   with open(fname, "rb") as f:
        fmt = 'HHI'
        raw=struct.pack(fmt,1,2,3)
        len=struct.calcsize(fmt)
        print(len)               # This shows 8, as expected 
        for raw in f.read(len):  # Expect this should read 8 bytes into raw
            print(type(raw))     # This says raw is an 'int', not a byte-array
            record=struct.unpack(fmt, raw ) # "TypeError: a bytes-like object is required, not 'int'"
            print(record)

如果您有足够的内存,您可能需要查看 iter_unpack() 进行优化。

请注意,在 3.7 中,默认值从字节更改为字符串。请参阅页面附近https://docs.python.org/3/library/struct.html#struct.pack


0
投票

您也可以使用海象运算符 (

:=
) 来完成此操作,我发现它更简洁且更具可读性:

fname = '/tmp/foobar.txt'
size = 2

with open(fname, 'rb') as fp:
    while chunk := fp.read(size):
        print(chunk)
echo 'foobar' > /tmp/foobar.txt

python iter-chunks.py

b'fo'
b'oo'
b'ba'
b'r\n'

这实现了OP要求的解决方案:

我想要前 8 个字节,然后迭代获取下一个 8 个字节,以及接下来的 8 个字节,依此类推,直到处理完整个文件

© www.soinside.com 2019 - 2024. All rights reserved.