在Python中读取二进制文件
我写了一个Python脚本,用来创建一个包含整数的二进制文件。
import struct
pos = [7623, 3015, 3231, 3829]
inh = open('test.bin', 'wb')
for e in pos:
inh.write(struct.pack('i', e))
inh.close()
这个脚本运行得很好,然后我尝试用下面的代码来读取'test.bin'文件。
import struct
inh = open('test.bin', 'rb')
for rec in inh:
pos = struct.unpack('i', rec)
print pos
inh.close()
但是它出错了,显示了一个错误信息:
Traceback (most recent call last):
File "readbinary.py", line 10, in <module>
pos = struct.unpack('i', rec)
File "/usr/lib/python2.5/struct.py", line 87, in unpack
return o.unpack(s)
struct.error: unpack requires a string argument of length 4
我想知道怎么用struct.unpack
来读取这个文件。
非常感谢,
Vipin
6 个回答
1
检查打包整数的大小:
>>> pos
[7623, 3015, 3231, 3829]
>>> [struct.pack('i',e) for e in pos]
['\xc7\x1d\x00\x00', '\xc7\x0b\x00\x00', '\x9f\x0c\x00\x00', '\xf5\x0e\x00\x00']
我们看到是4字节的字符串,这意味着读取时应该一次读取4个字节:
>>> inh=open('test.bin','rb')
>>> b1=inh.read(4)
>>> b1
'\xc7\x1d\x00\x00'
>>> struct.unpack('i',b1)
(7623,)
>>>
这就是原始的整数!将其扩展到一个读取循环的部分留给你自己去练习。
5
我觉得“for rec in inh”应该是用来读取'行'而不是'字节'。你想要的是:
while True:
rec = inh.read(4) # Or inh.read(struct.calcsize('i'))
if len(rec) != 4:
break
(pos,) = struct.unpack('i', rec)
print pos
或者正如其他人提到的:
while True:
try:
(pos,) = struct.unpack_from('i', inh)
except (some_exception...):
break
8
for rec in inh:
这种写法是一次读取一行数据,这对于处理二进制文件来说并不合适。你应该每次读取4个字节(可以用一个while
循环和inh.read(4)
来实现),或者一次性把所有数据都读到内存里,使用.read()
这个方法,然后再把每4个字节分开处理。第二种方法是最简单、最实用的,只要数据量不是特别大:
import struct
with open('test.bin', 'rb') as inh:
indata = inh.read()
for i in range(0, len(data), 4):
pos = struct.unpack('i', data[i:i+4])
print(pos)
如果你担心数据量会非常大(可能会超过你的内存),那么可以使用一个简单的生成器,这样的做法也很优雅:
import struct
def by4(f):
rec = 'x' # placeholder for the `while`
while rec:
rec = f.read(4)
if rec: yield rec
with open('test.bin', 'rb') as inh:
for rec in by4(inh):
pos = struct.unpack('i', rec)
print(pos)
第二种方法的一个主要优点是,by4
这个生成器可以很容易地调整(同时保持规范:每次返回一个二进制文件的4个字节数据),可以使用不同的缓冲策略,甚至可以回到第一种方法(先读取所有数据再分开处理),这可以被看作是“无限缓冲”,并且可以这样编写:
def by4(f):
data = inf.read()
for i in range(0, len(data), 4):
yield data[i:i+4]
这样做的同时,"应用逻辑"(也就是如何处理这些4字节的数据块)保持不变,并且与输入输出层是独立的(输入输出的部分被封装在生成器里面)。