我有一个读取二进制文件,然后使用struct.unpack()解压缩文件内容的函数。我的功能工作正常。如果/当我使用长的“格式”字符串解压缩整个文件时,速度更快。问题是有时字节对齐方式会发生变化,因此我的格式字符串(无效)看起来像是“ <10sHHb> llh”(这只是一个示例(通常更长)。有什么超灵巧/ pythonic的方式可以处理这种情况?
答案 0 :(得分:2)
没什么特别的,但是如果速度算得上重要,struct
模块的顶层函数就是包装器,它们必须针对格式字符串所对应的实际struct.Struct
实例重复地重新检查高速缓存;虽然必须制作单独的格式字符串,但可以避免重复进行缓存检查,从而解决了部分速度问题。
代替:
buffer = memoryview(somedata)
allresults = []
while buffer:
allresults += struct.unpack_from('<10sHHb', buffer)
buffer = buffer[struct.calcsize('<10sHHb'):]
allresults += struct.unpack_from('>llh', buffer)
buffer = buffer[struct.calcsize('>llh'):]
您会这样做:
buffer = memoryview(somedata)
structa = struct.Struct('<10sHHb')
structb = struct.Struct('>llh')
allresults = []
while buffer:
allresults += structa.unpack_from(buffer)
buffer = buffer[structa.size:]
allresults += structb.unpack_from(buffer)
buffer = buffer[structb.size:]
不,外观看起来并不好看,速度的提高也不太会让您震惊。但是您有奇怪的数据,所以这是最不易碎的解决方案。
如果您想要不必要的巧妙/易碎的解决方案,可以使用ctypes
自定义Structure
,在BigEndianStructure
内嵌套LittleEndianStructure
(s)来做到这一点,反之亦然。对于您的示例格式:
from ctypes import *
class BEStruct(BigEndianStructure):
_fields_ = [('x', 2 * c_long), ('y', c_short)]
_pack_ = True
class MainStruct(LittleEndianStructure):
_fields_ = [('a', 10 * c_char), ('b', 2 * c_ushort), ('c', c_byte), ('big', BEStruct)]
_pack_ = True
将为您提供一个可以做到的结构:
mystruct = MainStruct()
memoryview(mystruct).cast('B')[:] = bytes(range(25))
,然后按预期顺序获得结果,例如:
>>> hex(mystruct.b[0]) # Little endian as expected in main struct
'0xb0a'
>>> hex(mystruct.big.x[0]) # Big endian from inner big endian structure
'0xf101112'
虽然很聪明,但运行速度可能会变慢(根据我的经验,ctypes
属性查找很慢),而且与struct
模块功能不同,您不能仅将其分解为top-一行中的命名变量级别,就一直对属性进行访问。