Python解包结构不起作用

2024-09-24 20:38:47 发布

您现在位置: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    

有:

^{pr2}$

但是,Python返回:

struct.error: unpack requires a string argument of length 4

根据python struct.unpackdocumentation

The string must contain exactly the amount of data required by the format (len(string) must equal calcsize(fmt)).

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

编辑:

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

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

因此,正如您在read_timetrace函数中看到的,在if...else语句中,fmt被设置为'<'或{}。打印出来证实了这一点。在

但是你也应该知道我在windowsx64上工作(为了工作)。在

编辑2

这是完整的回溯,抱歉弄错了。在

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]

编辑3:

我将readline替换为read,并添加:

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

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]

Tags: inpytestreadlentemplateuserssuite
3条回答

len(fmt)=1时,表示fmt有值。如果fmt='h',那么fmt+'h'将是'hh'。因此,unpack()需要4个字节的数据,因为每个“h”都需要一个短整数(2个字节)。在

FWIW,您应该使用read(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()

输出

^{pr2}$

顺便说一句,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 '\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

后记

您的代码中有几个函数几乎执行相同的操作。这打破了DRY原则:不要重复你自己。这里有一种方法可以解决这个问题,使用部分函数应用程序。有关详细信息,请参阅functools docs。在

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)

是的,这稍微有些冗长,但它使代码更具可读性。在

格式的长度本身并不重要。重要的是你在那里指定了什么样的格式。例如,有一些格式规范指定一个字节甚至八个字节。所以这实际上取决于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真的是{},那么它应该可以正常工作:

^{pr2}$

所以我假设当出现错误时,fmt而不是只是>,而是其他会消耗额外2个字节的东西。尝试在unpack之前打印fmt。在

相关问题 更多 >