<p>FWIW,您应该使用<code>read(2)</code>,而不是{<cd2>}。如果<code>fmt</code>字符串真的是<code>'>'</code>,那么就不会得到这个错误。下面是一个简短的演示,它的性能符合预期。在</p>
<pre><code>from struct import unpack
fname = 'qbytes'
#Create a file of all byte values
with open(fname, 'wb') as f:
f.write(bytearray(range(256)))
def ReadWord(fid, fmt, addr):
fid.seek(addr)
s = fid.read(2)
s = unpack(fmt + 'h', s)
return s[0]
fid = open(fname, 'rb')
for i in range(16):
addr = i
n = 256*i + i+1
#Interpret file data as big-endian
print i, ReadWord(fid, '>', addr), n
fid.close()
</code></pre>
<p><strong>输出</strong></p>
^{pr2}$
<p>顺便说一句,<code>struct.unpack()</code><em>总是</em>返回一个元组,即使返回值是单个项。在</p>
<hr/>
<p>对二进制文件使用<code>readline(2)</code>可能会产生意外的结果。在上面代码的测试文件中,文件中有一个(Linux风格)换行符<code>\xa0</code>。因此,如果您将<code>s = fid.read(2)</code>更改为<code>s = fid.readline(2)</code>,开始时一切正常,但是在第10行,它崩溃了,因为它只读取一个字节,这是由于新行字符:</p>
<pre><code>from struct import unpack
fname = 'qbytes'
#Create a file of all byte values
with open(fname, 'wb') as f:
f.write(bytearray(range(256)))
def ReadWord(fid, fmt, addr):
fid.seek(addr)
s = fid.readline(2)
print repr(s),
s = unpack(fmt + 'h', s)
return s[0]
with open(fname, 'rb') as fid:
for i in range(16):
addr = i
n = 256*i + i+1
#Interpret file data as big-endian
print i, ReadWord(fid, '>', addr), n
</code></pre>
<p><strong>输出</strong></p>
<pre><code>0 '\x00\x01' 1 1
1 '\x01\x02' 258 258
2 '\x02\x03' 515 515
3 '\x03\x04' 772 772
4 '\x04\x05' 1029 1029
5 '\x05\x06' 1286 1286
6 '\x06\x07' 1543 1543
7 '\x07\x08' 1800 1800
8 '\x08\t' 2057 2057
9 '\t\n' 2314 2314
10 '\n'
Traceback (most recent call last):
File "./qtest.py", line 30, in <module>
print i, ReadWord(fid, '>', addr), n
File "./qtest.py", line 22, in ReadWord
s = unpack(fmt + 'h', s)
struct.error: unpack requires a string argument of length 2
</code></pre>
<hr/>
<h2>后记</h2>
<p>您的代码中有几个函数几乎执行相同的操作。这打破了<a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="nofollow">DRY</a>原则:不要重复你自己。这里有一种方法可以解决这个问题,使用部分函数应用程序。有关详细信息,请参阅<a href="https://docs.python.org/3/library/functools.html?module-functools#functools.partial" rel="nofollow">functools docs</a>。在</p>
<pre><code>from functools import partial
def ReadNumber(fid, datalen=1, fmt='>', conv='b', addr=0):
fid.seek(addr)
s = fid.read(datalen)
if len(s) != datalen:
raise IOError('Read %d bytes but expected %d at %d' % (len(s), datalen, addr))
return unpack(fmt+conv, s)[0]
ReadByte = partial(ReadNumber, datalen=1, conv='b')
ReadWord = partial(ReadNumber, datalen=2, conv='h')
ReadLong = partial(ReadNumber, datalen=4, conv='l')
ReadFloat = partial(ReadNumber, datalen=4, conv='f')
ReadDouble = partial(ReadNumber, datalen=8, conv='d')
</code></pre>
<p>您需要使用关键字来调用这些新函数。例如</p>
<pre><code>ReadLong(fid, fmt='>', addr=addr)
</code></pre>
<p>是的,这稍微有些冗长,但它使代码更具可读性。在</p>