Skip to main content
 首页 » 编程设计

python之如何在 Python 中复制 zlib 压缩器对象的内部状态

2025年05月04日8shangdawei

我必须压缩一长串字符串。我必须单独压缩它们。每个字符串的长度少于 1000 个字符。然而,其中许多字符串都有一个共同的前缀。因此,我想知道我是否可以通过首先压缩公共(public)前缀然后存储压缩器的状态并将字符串的后缀提供给它来分摊压缩成本。

如果您对如何在 Python 中完成此操作有任何建议,那就太好了。尽管我在标题中提到了 zlib,但任何其他标准模块也可以使用。在这个应用程序中,解压速度无关紧要,所以我可以承受解压速度很慢。

请您参考如下方法:

Python interface to zlib相当微薄,并且不提供对所有 zlib's capabilities 的访问.如果您可以构建自己的 zlib 接口(interface),那么您就可以完成您所要求的,甚至更多。

“和更多”与您单独压缩非常短的字符串这一事实有关,这从本质上限制了您可以获得的压缩量。由于这些字符串有一些共同的内容,您应该使用 zlib 的 deflateSetDictionary() 和 inflateSetDictionary() 函数来利用这一事实,并可能显着提高压缩率。公共(public)内容可以是您提到的公共(public)前缀,也可以是字符串中其他任何地方的公共(public)内容。您将定义一个固定字典以用于所有最大 32K 的字符串,其中包含字符串中经常出现的字节序列。您可以将最常见的序列放在 32K 的末尾,将不太常见的序列放在前面。如果这些字符串的多个类别具有不同的公共(public)序列,您可以根据需要创建一组字典并使用第一次调用 inflate() 返回的字典 ID 来选择字典。对于一个或多个词典,只需要确保压缩端和解压端存储的是相同的词典即可。

至于存储压缩状态,您可以使用 deflateCopy() 来实现。这是在 Python 中通过 copy() 方法提供的。我不确定这会给你带来很大的速度优势,尽管对于小字符串。

更新:

根据最近添加的评论,我相信您的用例是您根据请求将许多字符串中的一些发送给接收者。在这种情况下,可能有一种方法可以使用微不足道的 Python 接口(interface)获得更好的压缩。您可以将 flush 方法与 Z_SYNC_FLUSH 一起使用,以强制输出到目前为止已压缩的内容。这将允许您将请求的字符串系列视为单个压缩流。

该过程是您使用 compressobj() 启动一个压缩对象,在该对象上使用 compress() 请求的第一个字符串,收集该对象的输出(如果有的话),然后对对象执行 flush(Z_SYNC_FLUSH),收集剩余的输出。将 compress() 和 flush() 的组合输出发送到接收方,接收方已启动 decompressobj() 然后使用 decompress() 对该对象及其发送的内容进行解压缩,这将返回原始字符串。 (减压端无需冲洗。)

到目前为止,结果与仅压缩第一个字符串没有太大区别。好处是您可以重复该过程而无需创建新的压缩或解压缩对象。只需对下一个字符串使用 compress() 和 flush(),在另一端使用 decompress() 即可获取它。第二个字符串和所有后续字符串的优势在于,它们可以使用先前字符串的历史记录进行压缩。然后你不需要构建或使用任何固定的字典。您可以只使用先前请求的字符串的历史记录来提供良好压缩所需的素材。如果您的字符串平均长度为 1000 字节,最终发送的每个字符串都将受益于最近发送的 32 个字符串的历史记录,因为压缩的滑动窗口长度为 32K。

完成后,只需关闭对象即可。