Python struct.unpack无法正常工作

Max*_*AST 5 python

我试图运行这个:

def ReadWord(fid,fmt,Addr):
    fid.seek(Addr)
    s = fid.readline(2)
    s = unpack(fmt + 'h', s)
    if(type(s) == tuple):
        return s[0]
    else:
        return s    
Run Code Online (Sandbox Code Playgroud)

有:

len(s) = 2
len(fmt) = 1
calcsize(fmt) = 0
calcsize(fmt + 'h') = 2
Run Code Online (Sandbox Code Playgroud)

但是,Python返回:

struct.error:unpack需要长度为4的字符串参数

根据python struct.unpack 文档:

该字符串必须包含格式所需的数据量(len(字符串)必须等于calcsize(fmt)).

因此,如果我的字符串的长度是2并且calcsize fmt+'h'也是2,为什么python说"unpack需要一个长度为4的字符串参数"?

编辑:

谢谢你的所有答案.这是完整的代码:

http://qtwork.tudelft.nl/gitdata/users/guen/qtlabanalysis/analysis_modules/general/lecroy.py

因此,您可以在read_timetrace函数中看到,fmt设置为'<''>'if...else语句中.打印确认了这一点.

你也应该知道我正在使用windowsx64(工作).

EDIT2

这是完整的追溯,对不起这个错误.

Traceback (most recent call last):
  File "C:\Users\maxime.vast\Desktop\Test Campaign Template\Test Suite\Include\readLecroyTRCFile.py", line 139, in <module>
    read_timetrace("C:\Users\maxime.vast\Desktop\Test Campaign Template\Test Suite\Traces\KL.ES.001.001.trc")
  File "C:\Users\maxime.vast\Desktop\Test Campaign Template\Test Suite\Include\readLecroyTRCFile.py", line 60, in read_timetrace
    WAVE_ARRAY_1        = ReadLong(fid, fmt, aWAVE_ARRAY_1)
  File "C:\Users\maxime.vast\Desktop\Test Campaign Template\Test Suite\Include\readLecroyTRCFile.py", line 100, in ReadLong
    s = unpack(fmt + 'l', s)
struct.error: unpack requires a string argument of length 4
[Finished in 0.2s]
Run Code Online (Sandbox Code Playgroud)

EDIT3:

我替换readlineread并添加:

print "len(s) ", len(s)
print "len(fmt) ", len(fmt)
print "calcsize(fmt) ", calcsize(fmt)
print "calcsize(fmt + 'h') ", calcsize(fmt + 'h')
print "fmt ", fmt
Run Code Online (Sandbox Code Playgroud)

发挥ReadLong作用.

这是新的追溯:

len(s)  4
len(fmt)  1
calcsize(fmt)  0
calcsize(fmt + 'h')  2
fmt  <
len(s)  4
len(fmt)  1
calcsize(fmt)  0
calcsize(fmt + 'h')  2
fmt  <
len(s)  4
len(fmt)  1
calcsize(fmt)  0
calcsize(fmt + 'h')  2
fmt  <
len(s)  1
len(fmt)  1
calcsize(fmt)  0
calcsize(fmt + 'h')  2
fmt  <
Traceback (most recent call last):
  File "C:\Users\maxime.vast\Desktop\Test Campaign Template\Test Suite\Include\readLecroyTRCFile.py", line 143, in <module>
    read_timetrace("C:\Users\maxime.vast\Desktop\Test Campaign Template\Test Suite\Traces\KL.ES.001.001.trc")
  File "C:\Users\maxime.vast\Desktop\Test Campaign Template\Test Suite\Include\readLecroyTRCFile.py", line 60, in read_timetrace
    WAVE_ARRAY_1        = ReadLong(fid, fmt, aWAVE_ARRAY_1)
  File "C:\Users\maxime.vast\Desktop\Test Campaign Template\Test Suite\Include\readLecroyTRCFile.py", line 104, in ReadLong
    s = unpack(fmt + 'l', s)
struct.error: unpack requires a string argument of length 4
[Finished in 0.2s]
Run Code Online (Sandbox Code Playgroud)

PM *_*ing 4

FWIW,你应该使用read(2),而不是readline(2). 如果fmt字符串确实是'>'你不应该得到这个错误。这是一个按预期执行的简短演示。

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()
Run Code Online (Sandbox Code Playgroud)

输出

0 1 1
1 258 258
2 515 515
3 772 772
4 1029 1029
5 1286 1286
6 1543 1543
7 1800 1800
8 2057 2057
9 2314 2314
10 2571 2571
11 2828 2828
12 3085 3085
13 3342 3342
14 3599 3599
15 3856 3856
Run Code Online (Sandbox Code Playgroud)

顺便说一句,即使返回值是单个项目,也struct.unpack() 始终返回一个元组。


readline(2)在二进制文件上使用可能会产生意想不到的结果。在我的测试文件中,上面的代码\xa0中有一个(Linux 风格的)换行符。因此,如果你一开始一切s = fid.read(2)s = fid.readline(2)工作正常,但在第 10 行它会崩溃,因为它只读取一个字节,由于换行符:

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
Run Code Online (Sandbox Code Playgroud)

输出

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
Run Code Online (Sandbox Code Playgroud)

后记

您的代码中有多个函数几乎执行相同的操作。这违反了DRY原则:不要重复自己。这是解决这个问题的一种方法,使用部分函数应用程序。有关更多信息,请参阅functools 文档。

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') 
Run Code Online (Sandbox Code Playgroud)

您需要使用关键字来调用这些新函数。例如,

ReadLong(fid, fmt='>', addr=addr)
Run Code Online (Sandbox Code Playgroud)

确实,这有点冗长,但它使代码更具可读性。

  • +1 表示“read”而不是“readline”。现在OP已经澄清了这个问题,发生的事情是异常实际上是由“ReadLong”引发的,它需要4个字节。我想为什么会发生这种情况是因为“readline”遇到了行或文件结尾。一般来说,OP 应该使用“read”并检查所有字节是否可用并已读取。 (3认同)