我使用ctypes位字段来解析压缩的二进制数据。我将一条记录的数据作为字符串填充到并集中,然后将关键字段作为整数取出。
当缓冲区中没有null,但任何嵌入的null都会导致cytype截断字符串时,这种方法非常有效。
示例:
from ctypes import *
class H(BigEndianStructure):
_fields_ = [ ('f1', c_int, 8),
('f2', c_int, 8),
('f3', c_int, 8),
('f4', c_int, 2)
# ...
]
class U(Union):
_fields_ = [ ('fld', H),
('buf', c_char * 6)
]
# With no nulls, works as expected...
u1 = U()
u1.buf='abcabc'
print '{} {} {} (expect: 97 98 99)'.format(u1.fld.f1, u1.fld.f2, u1.fld.f3)
# Embedded null breaks it... This prints '97 0 0', NOT '97 0 99'
u2 = U()
u2.buf='ax00cabc'
print '{} {} {} (expect: 97 0 99)'.format(u2.fld.f1, u2.fld.f2, u2.fld.f3)
浏览ctypes源代码,我看到了两种设置char数组的方法,CharArray_set_value()和CharArray_set _raw()。看起来CharArray_set_raw()将正确处理null,而CharArray_set _value()则不会。
但我不知道如何调用原始版本。。。它看起来像一处房产,所以我希望有这样的东西:
ui.buf.raw = 'abcabc'
但这会产生:
AttributeError: 'str' object has no attribute raw
感谢任何指导。(包括完全不同的方法!)
(注意:我每秒需要处理数千条记录,因此效率至关重要。使用数组理解在结构中填充字节数组是可行的,但速度慢了100倍。)
您也可以在结构/联合之外创建原始字符串数组:
mystring = (c_char * 6).from_buffer(u2)
print mystring.raw
这样,您就不会有任何转换开销。我想知道为什么(c_char*6)在单独使用时与在结构/联合中使用时表现不同。。。
c_char*6
被处理为一个以nul结尾的字符串。改为切换到c_byte*6
,但失去了使用字符串初始化的便利性:
from ctypes import *
class H(BigEndianStructure):
_fields_ = [ ('f1', c_int, 8),
('f2', c_int, 8),
('f3', c_int, 8),
('f4', c_int, 2)
# ...
]
class U(Union):
_fields_ = [ ('fld', H),
('buf', c_byte * 6)
]
u1 = U()
u1.buf=(c_byte*6)(97,98,99,97,98,99)
print '{} {} {} (expect: 97 98 99)'.format(u1.fld.f1, u1.fld.f2, u1.fld.f3)
u2 = U()
u2.buf=(c_byte*6)(97,0,99,97,98,99)
print '{} {} {} (expect: 97 0 99)'.format(u2.fld.f1, u2.fld.f2, u2.fld.f3)
输出:
97 98 99 (expect: 97 98 99)
97 0 99 (expect: 97 0 99)