[英]Python: What's the best way to unpack a struct array from binary data
我正在解析二进制文件格式(OpenType 字体文件)。 该格式是许多不同结构类型的复杂树,但一个重复出现的模式是具有特定格式的记录数组。 我使用struct.unpack
编写代码一次获取一条记录。 但我想知道是否有一种方法可以解析整个记录数组?
以下是一种特定记录数组的解压缩结果示例:
[{'glyphID': 288, 'paletteIndex': 0}, {'glyphID': 289, 'paletteIndex': 1}, {'glyphID': 518, 'paletteIndex': 0}, ...] list
这就是我目前正在做的事情:我创建了一个通用的 function 来解压缩任意记录数组(在任何给定调用中的记录格式一致)。
def tryReadRecordsArrayFromBuffer(buffer, numRecords, format, fieldNames):
recordLength = struct.calcsize(format)
array = []
index = 0
for i in range(numRecords):
record = {}
vals = struct.unpack(format, buffer[index : index + recordLength])
for k, v in zip(fieldNames, vals):
record[k] = v
array.append(record)
index += recordLength
return array
buffer
参数是一个字节序列,大小至少为数组的大小,第一个记录在序列的开头被解包。
根据正在读取的记录数组的类型, format
参数是一个struct
格式字符串。 在一种情况下,格式字符串可能是">3H"
; 在另一种情况下,它可能是">4s2H"
; 等。对于上面的结果示例,它是">2H"
。
fieldNames
参数是给定记录类型中字段名称的字符串序列。 对于上面的结果示例,这是("glyphID", "paletteIndex")
。
因此,我正在遍历缓冲区(字节序列数据),获取顺序切片并一次一个地解包记录,为每条记录创建一个字典并将它们附加到array
列表中。
有没有更好的方法来做到这一点,比如在某个模块中unpack
的方法允许将格式定义为结构数组并立即解包整个 shebang?
看看 kaitai - https://kaitai.io/ ,一个用于跨多种语言解析二进制文件的库,具有以独立于语言的方式定义文件格式的框架。
它能够在文件格式中定义条件,并根据需要调整解析。 虽然学习曲线并非立即微不足道,但也不是太难。
假设您想自己做而不是使用外部库,则需要考虑一些可以提高性能/代码的事情:
struct.unpack_from(format, buffer, offset=0)
而不是当前方法,因为buffer[index: index + recordLength]
可能会创建新对象并复制 memory ,这不是必需的如果要解压相同格式的数组,可以使用struct.iter_unpack(format, buffer)
进一步改进它,然后迭代结果:
import itertools import struct def tryReadRecordsArrayFromBuffer(buffer, numRecords, format, fieldNames): unpack_iter = struct.iter_unpack(buffer, format) return [ # I like this better than dict(zip(...)) but you can also do that {k: v for k, v in zip(fieldNames, vals)} # We use `islice` to only take the first numRecords values for vals in itertools.islice(unpack_iter, numRecords) ]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.