Py学习  »  Python

尝试在python中循环二进制文件

abelenky • 5 年前 • 1342 次点击  

我正试图使用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社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/40320
 
1342 次点击  
文章 [ 3 ]  |  最新文章 5 年前
Harvey
Reply   •   1 楼
Harvey    6 年前

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

   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)

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

注意,在3.7中,默认值从字节变为字符串。见本页末尾 https://docs.python.org/3/library/struct.html#struct.pack

snakecharmerb
Reply   •   2 楼
snakecharmerb    6 年前

这个 iter 内置的,如果传递了一个可调用的,并且一个sentinel值将重复调用该可调用的,直到返回sentinel值。

所以你可以用 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
gdlmx
Reply   •   3 楼
gdlmx    6 年前

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)