【问题标题】:How can one copy the internal state of zlib compressor object in Python如何在 Python 中复制 zlib 压缩器对象的内部状态
【发布时间】:2012-07-26 05:13:55
【问题描述】:

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

如果您对如何在 Python 中完成此任务有任何建议,那就太好了。尽管我在标题中提到了 zlib,但任何其他标准模块也可以使用。在这个应用中解压的速度并不重要,所以我可以承受解压的速度相当慢。

【问题讨论】:

  • 这个列表中有多少个字符串?考虑使用en.wikipedia.org/wiki/Trie ?
  • @cldy 哦,这不在我的控制范围内。我必须压缩这些字符串,然后根据需要发送几个不同的子集。

标签: python compression zlib


【解决方案1】:

Python interface to zlib 相当少,并且不提供对所有zlib's capabilities 的访问。如果您可以构建自己的 zlib 接口,那么您可以做您所要求的,等等。

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

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

更新:

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

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

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

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

【讨论】:

  • 是的,我已经熟悉了 deflateSetDictionary() 和 inflateSetDictionary(),所以我在 Python 的标准库中寻找可以公开压缩字典的东西。赞成,因为这对其他人有帮助。我必须发送前缀,因为我只需要发送一小部分字符串,而且它们不需要有共同的前缀。这是用于离线处理以创建查找表。是的,Python 的 zlib 真的很穷,不知道为什么。
  • 非常感谢您的更新。不幸的是,我无法在运行时进行压缩,并且在输入公共前缀之后,我考虑过使用 flush(Z_SYNC_FLUSH)。希望我能保持那个状态,因为一旦我输入后缀,那个状态就消失了。在字里行间阅读,我认为您是在说即使该状态消失了,它也很有可能“记住”前缀。我需要的是具有公共前缀的后续字符串压缩得更快。我关心压缩速度,而不是解压缩。
  • 我确实需要每个字符串都可以独立解压。
  • 您可以保持状态以加快压缩速度。请参阅 Python 的 zlib 接口中提到的 copy() 方法。根据前缀的长度,这可能会也可能不会成功。复制操作中需要复制大量数据。
  • 请在问题中描述您的应用程序。这样可以更轻松地提供有用的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多