我正在尝试使用 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)
如何将我的文件作为一系列结构读取,并将它们分别打印出来?
内置的 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
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)
我以前从未使用过这个,但它看起来像是一个初始化问题:
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
您也可以使用海象运算符 (
:=
) 来完成此操作,我发现它更简洁且更具可读性:
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 个字节,依此类推,直到处理完整个文件