当我的字符串长度正确时,为什么struct.unpack()会抛出异常?

时间:2012-04-19 02:10:03

标签: python struct

我有一个文件,其中一些行是我可以忽略的元数据,一些行是struct.pack调用的打印结果。假设f.txt是:

key: 3175
\x00\x00\x00\x00\x00\x00\x00\x00
key: 3266
\x00\x00\x00\x00\x00\x00\x00\x00

在这种情况下,以“key”开头的行是元数据,字节字符串是我想要提取的值。同样在这种情况下,两个字节的字符串行是用struct.pack('d',0)生成的。以下代码是我想要做的:

import struct
for line in open('f.txt', 'r'):      
  # if not metadata, remove newline character and unpack
  if line[0:3] != 'key':
    val = struct.unpack('d', line[0:-1])
    appendToList(val) # do something else with val

有了这个,我得到:“struct.error:unpack需要一个长度为8的字符串参数。”

如果我们稍微修改一下代码:

import struct
for line in open('f.txt', 'r'):      
  # if not metadata, remove newline character and unpack
  if line[0:3] != 'key': print line[:-1]

然后输出符合预期:

\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00

如果我将字节串直接放入解包调用,那么我就成功了:

import struct
# successful unpacking
struct.unpack('d', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')

我尝试将以下变量行传递给unpack,所有这些变量都给出相同的结果:

str(line)
repr(line)
b"%s" % line

2 个答案:

答案 0 :(得分:3)

文本文件中的实际字节是您在python控制台上看到的字符串转义字节,而不是它们代表的二进制字节。

例如,您的文本文件包含\x00(四个字节长),而不是空字节(一个字节长)。

在struct可以使用之前,你需要对这个文本(转换为二进制形式)进行解读。

(请注意,您的文件格式不是很好,因为您可以想象有一个数字的行,但以'key:'开头!例如'key: \x00\x00\x00'是有效数字6.8388560679e-313 !如果您在元数据和每隔一行的值之间切换,您应该只跟踪您所在的行号并进行相应的解析。)

这里有一个比其他人简单得多的解决方案。

Python有一个名为string_escape的内置编解码器,它将python-escape代码转换为它们代表的二进制字节:

for line in thefile:
    if line[0:3] != 'key':
        binaryline = line[:-1].decode('string_escape')
        val = struct.unpack('d', binaryline)

如果您有这些双精度值的大列表并希望将它们有效地存储在数组结构中,请考虑使用array模块而不是struct

vals = array.array('d')

for line in thefile:
    if line[0:3] != 'key':
        binaryline = line[:-1].decode('string_escape')
        # appends binaryline to vals array, interpreting as a double
        vals.fromstring(binaryline)

答案 1 :(得分:0)

表示txt文件中的字符串:

\x00\x00\x00\x00\x00\x00\x00\x00

在python中它实际上是:

\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00

所以你应该解析这个字符串并转换它。对于您的示例,使用以下代码可以得到您想要的:

s = line.strip().split('\\x')
r = ''
for v in s:
    if len(v) > 0:
        print v
        r += struct.pack('b', int(v, 16))
val = struct.unpack('d', r)[0]
print val