我正在尝试处理二进制格式,如下所示:
http://dabeaz.blogspot.jp/2009/08/python-binary-io-handling.html
>>> from ctypes import *
>>> class Point(Structure):
>>> _fields_ = [ ('x',c_double), ('y',c_double), ('z',c_double) ]
>>>
>>> g = open("foo","rb") # point structure data
>>> q = Point()
>>> g.readinto(q)
24
>>> q.x
2.0
我已经定义了头的结构,并试图将数据读入我的结构,但我遇到了一些困难。 我的结构是这样的:
class BinaryHeader(BigEndianStructure):
_fields_ = [
("sequence_number_4bytes", c_uint),
("ascii_text_32bytes", c_char),
("timestamp_4bytes", c_uint),
("more_funky_numbers_7bytes", c_uint, 56),
("some_flags_1byte", c_byte),
("other_flags_1byte", c_byte),
("payload_length_2bytes", c_ushort),
]
For integer type fields like c_int, a third optional item can be given. It must be a small positive integer defining the bit width of the field.
因此,对于("more_funky_numbers_7bytes", c_uint, 56),
我试图将该字段定义为7字节字段,但得到的错误是:
ValueError: number of bits invalid for bit field
所以我的第一个问题是,如何定义一个7字节的int字段?
然后,如果我跳过这个问题并注释掉“更多有趣的数字”字段,得到的数据将加载到。。但正如预期的那样,只有1个字符被加载到“ascii_32bytes”中。出于某种原因,返回16
,我假设是它读入结构的计算字节数。。。但是如果我在注释我的“funky number”字段,而“ascii_text_32bytes”只给出一个字符(1个字节),那不应该是13,而不是16???
然后我尝试将char字段分解成一个单独的结构,并在头结构中引用它。但那也不管用。。。
class StupidStaticCharField(BigEndianStructure):
_fields_ = [
("ascii_text_1", c_byte),
("ascii_text_2", c_byte),
("ascii_text_3", c_byte),
("ascii_text_4", c_byte),
("ascii_text_5", c_byte),
("ascii_text_6", c_byte),
("ascii_text_7", c_byte),
("ascii_text_8", c_byte),
("ascii_text_9", c_byte),
("ascii_text_10", c_byte),
("ascii_text_11", c_byte),
.
.
.
]
class BinaryHeader(BigEndianStructure):
_fields_ = [
("sequence_number_4bytes", c_uint),
("ascii_text_32bytes", StupidStaticCharField),
("timestamp_4bytes", c_uint),
#("more_funky_numbers_7bytes", c_uint, 56),
("some_flags_1byte", c_ushort),
("other_flags_1byte", c_ushort),
("payload_length_2bytes", c_ushort),
]
所以,任何关于如何:
更新
我发现了一个结构,似乎工作。。。
class BinaryHeader(BigEndianStructure):
_fields_ = [
("sequence_number_4bytes", c_uint),
("ascii_text_32bytes", c_char * 32),
("timestamp_4bytes", c_uint),
("more_funky_numbers_7bytes", c_byte * 7),
("some_flags_1byte", c_byte),
("other_flags_1byte", c_byte),
("payload_length_2bytes", c_ushort),
]
然而,现在我剩下的问题是,为什么在使用^{
f = open(binaryfile, "rb")
mystruct = BinaryHeader()
f.readinto(mystruct)
它返回的是52
,而不是预期的51
。那个额外的字节从哪里来,又到哪里去了?
更新2
对于那些感兴趣的人,这里有一个example的替代struct
方法来将值读入eryksun提到的namedtuple:
>>> record = 'raymond \x32\x12\x08\x01\x08'
>>> name, serialnum, school, gradelevel = unpack('<10sHHb', record)
>>> from collections import namedtuple
>>> Student = namedtuple('Student', 'name serialnum school gradelevel')
>>> Student._make(unpack('<10sHHb', record))
Student(name='raymond ', serialnum=4658, school=264, gradelevel=8)
此行定义实际上用于定义bitfield:
这是不对的。位字段的大小应小于或等于类型的大小,因此
c_uint
最多应为32,一个额外的位将引发异常:使用位字段的示例:
你需要的是7个字节,所以你最终所做的是正确的:
至于结构的大小,它将是52,32位处理器上的4个字节上的额外字节将填充到align the structure,64位处理器上的8个字节。这里:
文件中的多余字节填充在
other_flags_1byte
和payload_length_2bytes
之间:当涉及到文件格式和网络协议时,这是一个问题。若要将其更改为1,请将其打包:
文件将是:
至于
struct
,在你的情况下,这不会使事情变得更容易。遗憾的是,它不支持格式中的嵌套元组。例如:此结果不能使用
namedtuple
,您仍然可以根据索引对其进行解析。如果你能做一些像'>I(32c)(I)(7B)(B)(B)H'
这样的事情,它就会起作用。自2003年以来,(Extend struct.unpack to produce nested tuples)已在此处请求此功能,但此后未执行任何操作。相关问题 更多 >
编程相关推荐