próbuję obsłużyć format binarny, wzorując się tutaj:Parsing danych binarnych na obiekcie Structure ctypes przez readinto()
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
mam zdefiniowanej struktury mojego nagłówka i próbuję odczytać dane w mojej strukturze, ale mam pewne trudności. Moja struktura jest tak:
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),
]
ctypes documentation mówi:
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.
Więc dla ("more_funky_numbers_7bytes", c_uint, 56),
Próbowałem zdefiniować boiska w polu 7 bajtów, ale dostaję błąd:
ValueError: number of bits invalid for bit field
Więc moim pierwszym problemem jest jak zdefiniować 7-bajtowe pole int?
Następnie Jeśli pominę ten problem i skomentuję pole "more_funky_numbers_7bytes", wynikowe dane zostaną wczytane .. ale zgodnie z oczekiwaniami tylko 1 znak zostanie załadowany do "ascii_text_32bytes". I z jakiegoś powodu zwraca 16
, który zakładam, jest obliczoną liczbą bajtów, które odczytał w strukturze ... ale jeśli skomentuję moje pole "numer funky" i "" ascii_text_32bytes "to tylko jeden znak (1 bajt) nie powinno to być 13, a nie 16 ???
Potem próbowałem wyłamaniu pola char do osobnej struktury i odniesienia, który od wewnątrz mojego struktury nagłówka. Ale to nie działa albo ...
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),
]
Więc jakieś pomysły jak:
- zdefiniować pole 7 bajtów (które I'l Muszę do dekodowania przy użyciu określonej funkcji)
- Definiowanie statycznego pola char 32 bajtów
UPDATE
Znalazłem strukturę, która wydaje się działać ...
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),
]
Teraz pozostaje moje pytanie, dlaczego podczas używania .readinto()
:
f = open(binaryfile, "rb")
mystruct = BinaryHeader()
f.readinto(mystruct)
Powraca 52
, a nie oczekuje, 51
. Skąd pochodzi ten dodatkowy bajt i dokąd zmierza?
UPDATE 2 Dla zainteresowanych oto example alternatywnego struct
metody do odczytu wartości do namedtuple wspomnianym przez 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)
Jeśli spojrzysz na plik binarny za pomocą edytora heksadecymalnego, czy widzisz 51 bajtów? Co mówi "len (mystruct)"? –
Tak, plik 'binaryfile' ma ponad 50 KB. 'len (mystruct)' nie wydaje się działać, ale 'sizeof (mystruct)' zwraca 52 ... – monkut
Możesz dodać '_pack_ = 1' do definicji, ale rozważ użycie modułu' struct' z '' namedtuple' zamiast tego. – eryksun