Python struct.unpack不工作

Python struct.unpack不工作,python,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 与: 但是,Python返回: struct.error:解包需要长度为4的字符串参数 根据pythonstruct.

我正在尝试运行以下命令:

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    
与:

但是,Python返回:

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

根据python
struct.unpack

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

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

编辑:

谢谢你的回答。以下是完整的代码:

因此,正如您在
read\u 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]
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]
len(s)4
len(fmt)1
calcsize(fmt)0
计算(fmt+‘h’)2
fmt<
莱恩(s)4
len(fmt)1
calcsize(fmt)0
计算(fmt+‘h’)2
fmt<
莱恩(s)4
len(fmt)1
calcsize(fmt)0
计算(fmt+‘h’)2
fmt<
莱恩(s)1
len(fmt)1
calcsize(fmt)0
计算(fmt+‘h’)2
fmt<
回溯(最近一次呼叫最后一次):
文件“C:\Users\maxime.vast\Desktop\Test Campaign Template\Test Suite\Include\readLecroyTRCFile.py”,第143行,在
阅读时间跟踪(“C:\Users\maxime.vast\Desktop\Test Campaign Template\Test Suite\Traces\KL.ES.001.001.trc”)
文件“C:\Users\maxime.vast\Desktop\Test Campaign Template\Test Suite\Include\readLecroyTRCFile.py”,第60行,在read\u timetrace中
WAVE_阵列_1=ReadLong(fid、fmt、aWAVE_阵列_1)
文件“C:\Users\maxime.vast\Desktop\Test Campaign Template\Test Suite\Include\readLecroyTRCFile.py”,第104行,ReadLong格式
s=拆包(fmt+l',s)
struct.error:解包需要长度为4的字符串参数
[在0.2秒内完成]

格式的长度本身并不重要。重要的是你在那里指定了什么样的格式。例如,有指定一个字节甚至八个字节的格式规范。因此,这实际上取决于
s
中应有多少字符的格式

例如:

>>> struct.unpack('b', 'A')
(65,)
>>> struct.unpack('L', 'A')

Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    struct.unpack('L', 'A')
error: unpack requires a string argument of length 4
>>> struct.unpack('L', 'AAAA')
(1094795585,)

因此,我假设当出现错误时,
fmt
不仅仅是
,而是会消耗额外2个字节的其他内容。在
解包之前尝试打印
fmt
作为
len(fmt)
=1,这意味着
fmt
具有值。如果
fmt
='h',那么
fmt+'h'
将是'hh'。因此,unpack()需要4字节的数据,因为每个“h”需要一个短整数(2字节)。

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()
输出

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
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
顺便说一句,
struct.unpack()
始终返回一个元组,即使返回值是单个项


在二进制文件上使用
readline(2)
可能会产生意外的结果。在上面代码中的我的测试文件中,文件中有一个(Linux风格)换行符
\xa0
。因此,如果将
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
输出

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
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
您需要使用关键字来调用这些新函数。例如

ReadLong(fid, fmt='>', addr=addr)

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

既然您添加了完整的文件,请也添加您得到的完整回溯。@MathersMax:您真的不应该使用
.readline()
读取二进制文件。我刚刚注意到另一个问题:您正在以文本模式打开波形文件。您应该以二进制模式打开它,因为在Windows上的文本模式下,
“\x0d\x0a”
序列在阅读时会被翻译成
”\x0a“
。@MatherMax我可以看出您是这里的新成员-很高兴您根据评论进行了编辑,接受了答案并获得了所需的帮助!将答案编辑成问题通常不是一个好主意,尤其是当你得到了一个公认的答案时。也许你可以移动那个编辑。祝你一切顺利!我将在我的答案中再添加一点代码,说明如何减少所有
Readxxx()
函数的重复。+1表示
read
,而不是
readline
。既然OP已经澄清了这个问题,那么发生的事情就是异常实际上是由
ReadLong
引发的,它需要4个字节。我想这可能是因为
readline
遇到了行或文件结尾。通常,OP应该使用
read
并检查所有字节是否可用并已读取。
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') 
ReadLong(fid, fmt='>', addr=addr)