Python:从二进制数据解包结构数组的最佳方法是什么

2024-05-13 14:03:52 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在解析二进制文件格式(OpenType字体文件)。该格式是一个由许多不同结构类型组成的复杂树,但其中一个重复出现的模式是拥有一个特定格式的记录数组。我已经使用struct.unpack编写了代码来一次获取一条记录。但是我想知道我是否缺少一种方法来解析整个记录数组

以下是一种特定类型记录数组的未打包结果示例:

[{'glyphID': 288, 'paletteIndex': 0}, {'glyphID': 289, 'paletteIndex': 1}, {'glyphID': 518, 'paletteIndex': 0}, ...]    list

这就是我目前正在做的:我创建了一个通用函数来解包任意记录数组(在任何给定调用中都是一致的记录格式)

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")

因此,我正在单步遍历缓冲区(字节序列数据),获取序列片,并一次一个地解压缩记录,为每个记录创建一个dict,并将它们附加到array列表中

有没有更好的方法来实现这一点,在某些模块中使用类似unpack的方法,允许将格式定义为结构数组并立即解包整个shebang


Tags: 方法format示例类型indexbuffer格式记录
1条回答
网友
1楼 · 发布于 2024-05-13 14:03:52

看看kaitai-https://kaitai.io/,这是一个跨多种语言解析二进制文件的库,它有一个以独立于语言的方式定义文件格式的框架

它能够在文件格式内定义条件,并根据需要调整解析。虽然学习曲线不是很简单,但也不是很难


假设你想自己做而不使用外部库,需要考虑的一些事情可以改善穿孔/代码:

  1. 使用^{}而不是当前方法,因为buffer[index : index + recordLength]可能正在创建新对象并复制不需要的内存
  2. 如果要解压缩相同格式的数组,可以使用^{}进一步改进它,然后迭代结果:

    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)
        ]
    

相关问题 更多 >