GZIP 最多字节限制,无需复制

GZIP Up To Byte Limit Without Copy

我想使用 gzip 将记录打包到 io.ByteIO 的列表中。我想为每个我不想超过的包设置一个 max_size。问题是我不知道在我这样做之前我是否会用新记录超过那个尺寸。一旦它超过了尺寸,我就没有好的方法来撤消该添加。

def pack_gz_records(records: List[any], max_size: int) -> List[io.BytesIO]:
    packets = []
    
    mem_file = io.BytesIO()
    gz = gzip.GzipFile(fileobj=mem_file, mode="w")

    for record in records:
        if gz.size >= max_size:
            # Size exceeded limit. Add this mem file to the package and cut a new mem file
            mem_file.seek(0)
            packets.append(mem_file)
            mem_file = io.BytesIO()
            gz = gzip.GzipFile(fileobj=mem_file, mode="w")
        
        gz.write(serialize(record))

    if gz.size:
        mem_file.seek(0)
        packets.append(mem_file)

    return packets

有没有一种方法可以有效地撤消写入或“查看”写入,而无需在写入前复制每条记录的所有字节?

是的。使用 zlib 库(而不是 gzip)。使用 wbits=31 到 select gzip 格式创建压缩对象。 copy() 函数可以在添加下一条记录之前复制压缩对象。复制后,将下一条记录添加到原始对象并用 Z_BLOCK 刷新。如果结果加上 gzip 尾部的一些余量,没有超过您的限制,则删除副本。如果确实过去了,则删除过去的对象,然后返回并完成(用 Z_FINISH 刷​​新)复制对象上的压缩。

这假设您的记录至少有几 K 大小,因此压缩不会受到刷新的显着影响。如果您的记录很小,您应该在刷新之前压缩几条记录。 (用每次刷新的记录数进行实验以衡量压缩影响。)如果你喜欢,当你超过限制并备份时,你可以通过二进制搜索来确定记录数填满就好了。