在 msgpack 0.6 中获取字节偏移量

Getting byte offsets in msgpack 0.6

在我的场景中,我需要允许随机访问使用 msgpack 序列化的单个项目。 IE。给定一个二进制文件和一个项目索引,我想跳转到文件中的那个位置并反序列化这个项目。

为了获取每个项目的字节偏移量,我使用 mgspack.Unpackerunpack 函数。在 mgspack 0.5 中,unpack 接受一个可选参数 write_bytes,它是一个在序列化之前在原始数据字符串上调用的挂钩。计算这个字符串的 len 可以得到项目的大小(以字节为单位),这样我就可以累积字节偏移量。

自 msgpack 0.6 以来,write_bytes 参数不再被接受,我没有找到任何替代品给我 raw 输入字符串或消耗的字节数阅读一个项目后。

这是我用来创建索引的函数。函数 returns 将索引作为字节偏移列表。每个条目 index[i] 都包含项目 i 的字节偏移量。关键部分是 unpacker.unpack(write_bytes=hook) 调用,它不再接受任何属性。

def index_from_recording(filename):
    # create empty index
    index = []

    # hook that keeps track of the byte offset of the `msgpack.Unpacker`
    hook = ByteOffsetHook()

    with open(filename, "rb") as f:
        # create the `msgpack.Unpacker`
        unpacker = msgpack.Unpacker(f)
        try:
            while True:
                # add current offset to index
                index.append(hook.offset)

                # unpack (and discard) next item.
                # The `hook` keeps track of the read bytes
                unpacker.unpack(write_bytes=hook)  # <== `write_bytes` not accepted since 0.6
        except msgpack.OutOfData:
            pass

    return index

ByteOffsetHook定义如下。钩子简单地计算原始输入字符串的 len 并累积它。

class ByteOffsetHook(object):
    def __init__(self):
        self.offset = 0

    def __call__(self, data):
        self.offset += len(data)

为了调试,您可以使用此函数生成虚拟录音。

def serialize_dummy_recording(filename):
    with open(filename, "wb") as f:
        for serialized_sample in [msgpack.packb({'x': i}) for i in range(10)]:
            f.write(serialized_sample)


def main():
    filename = "test.rec"
    if not os.path.exists(filename):
        serialize_dummy_recording(filename)

    index = index_from_recording(filename)
    print(index)


if __name__ == "__main__":
    main()

我发现 tell 方法返回 Unpacker 的当前字节偏移量。但是,在删除参数的 latest documentation that I could find. Also the write_bytes parameter is not declared as deprecated as mentioned in the commit 中没有描述此行为。

创建索引的工作函数现在如下所示:

def index_from_recording(filename):
    # create empty index
    index = []

    with open(filename, "rb") as f:
        # create the `msgpack.Unpacker`
        unpacker = msgpack.Unpacker(f)
        try:
            while True:
                # add current offset to index
                index.append(unpacker.tell())

                # unpack (and discard) next item
                unpacker.unpack()
        except msgpack.OutOfData:
            pass

    return index