I am trying to handle binary format, following the example here:
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")
I have defined the structure of my header and I am trying to read the data in my structure, but I have some difficulties. My structure is as follows:
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), ]
The ctypes documentation says:
For integer type fields, such as c_int, the third optional element may be given. This should be a small positive integer defining the bit width of the field.
So, for ("more_funky_numbers_7bytes", c_uint, 56), I tried to define the field as a field of 7 bytes, but I get an error message:
ValueError: number of bits invalid for the bit field
So my first problem is how to define a 7 byte int field?
Then, if I skip this problem and comment out the "more_funky_numbers_7bytes" field, the resulting data will load in ... but as expected, only 1 character is loaded in "ascii_text_32bytes". And for some reason it returns 16 , which I assume is the calculated number of bytes that it reads into the structure ... but if I comment out my "funky number" and "ascii_text_32bytes" fields, it gives only one char (1 byte), not should be 13, not 16 ???
Then I tried to pull the char field into a separate structure and reference it from my header structure. But this does not work ...
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), ]
So, any ideas like:
- Define a field of 7 bytes (which I will need to decode using a specific function)
- Define a static char field of 32 bytes
UPDATE
I found a structure that seems to work ...
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), ]
Now, however, my remaining question is why when using .readinto() :
f = open(binaryfile, "rb") mystruct = BinaryHeader() f.readinto(mystruct)
It returns 52 , not expected, 51 . Where does this extra byte come from, and where does it go?
UPDATE 2 For those interested in an example of an alternative struct method for reading values ββin namedtuple mentioned by eryksun:
>>> 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)