【问题标题】:GZIP Up To Byte Limit Without CopyGZIP 达到字节限制,无需复制
【发布时间】:2021-12-28 15:20:06
【问题描述】:

我想使用 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

有没有办法撤消写入,或以有效的方式“窥视”写入,而无需在写入之前复制每条记录的所有字节?

【问题讨论】:

  • 我认为在你写之前没有办法知道会写多少。我建议您将限制设置为比您实际想要的低一点,这样稍微超出一点仍然是可以接受的。
  • 如果某条记录太大而无法压缩到小于您的最大大小,您会怎么做?
  • @MarkAdler 在我的情况下这将是一个错误,所以我并不担心

标签: python gzip


【解决方案1】:

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

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

【讨论】:

  • 我会看看这种方法。记录本身并不大,但有数十亿条记录在实时流中进行处理。 bin 搜索方法将如何工作?是否需要先将记录添加到 gzip 中才能确定剪切的位置?
  • 假设您一次添加 32 条记录,直到达到限制。现在你有 32 个不合适。使用相同的对象复制方法尝试添加其中的前 16 个。也太多了。现在尝试添加 8。这很有效。好的,12 点怎么样。是的。 14?不。试试 13。那合身!我们完成了。
  • 我现在明白你所说的 bin 搜索是什么意思了。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-12
  • 1970-01-01
  • 2010-12-14
  • 2013-03-11
  • 2011-03-25
  • 1970-01-01
相关资源
最近更新 更多