【问题标题】:What is the best compression algorithm for small 4 KB files?小 4 KB 文件的最佳压缩算法是什么?
【发布时间】:2025-03-27 02:40:02
【问题描述】:

我正在尝试压缩每个大小约为 4 KB 的 TCP 数据包。数据包可以包含任何字节(从 0 到 255)。我发现的所有压缩算法基准都是基于较大的文件。我没有找到任何可以比较不同算法对小文件的压缩率的东西,这正是我所需要的。我需要它是开源的,以便它可以在 C++ 上实现,例如没有 RAR。对于大小约为 4 KB 的小文件,可以推荐什么算法? LZMA? HACC? ZIP? gzip? bzip2?

【问题讨论】:

  • 这是因为您想优化带宽使用吗?或者这是一个性能问题?如果是前者,那么最好的办法就是全部尝试一下,看看它们的外观。如果是后者,您可能会发现按原样发送数据包会比 compress->send->decompress 例程更快。
  • OJ:不一定……有些环境的带宽非常有限。如果他甚至关心压缩 TCP 数据包,那么他很有可能在这样的环境中工作。
  • 此外,有许多连接对带宽总使用量有上限,因此压缩数据包将有助于他们节省一些带宽。

标签: compression


【解决方案1】:

选择最快的算法,因为您可能关心实时执行此操作。通常对于较小的数据块,算法的压缩率大致相同(给定或取几个字节),主要是因为算法除了负载之外还需要传输字典或霍夫曼树。

出于多种原因,我强烈推荐 Deflate(zlib 和 Zip 使用)。该算法非常快,经过良好测试,获得 BSD 许可,并且是 Zip 需要支持的唯一压缩(根据 infozip Appnote)。除了基础之外,当它确定压缩比解压缩大小大时,有一个 STORE 模式,它只为每个数据块添加 5 个字节(最大块为 64k 字节)。除了 STORE 模式,Deflate 支持两种不同类型的 Huffman 表(或字典):动态和固定。动态表意味着霍夫曼树作为压缩数据的一部分进行传输,并且是最灵活的(对于不同类型的非随机数据)。固定表的优点是所有解码器都知道该表,因此不需要包含在压缩流中。解压(或膨胀)代码相对容易。我直接基于 zlib 编写了 Java 和 Javascript 版本,它们的性能相当不错。

提到的其他压缩算法都有其优点。我更喜欢 Deflate,因为它在压缩步骤,尤其是在解压缩步骤中的运行时性能。

澄清一点:Zip 不是压缩类型,它是一个容器。为了进行数据包压缩,我会绕过 Zip,只使用 zlib 提供的 deflate/inflate API。

【讨论】:

    【解决方案2】:

    如果您想“压缩 TCP 数据包”,您可以考虑使用 RFC 标准技术。

    • RFC1978 PPP 预测器压缩协议
    • RFC2394 使用 DEFLATE 压缩 IP 负载
    • RFC2395 使用 LZS 的 IP 有效负载压缩
    • RFC3173 IP 负载压缩协议 (IPComp)
    • RFC3051 使用 ITU-T V.44 数据包方法的 IP 有效负载压缩
    • RFC5172 协商使用 IPv6 控制协议进行 IPv6 数据报压缩
    • RFC5112 用于信令压缩的存在特定静态字典 (Sigcomp)
    • RFC3284 VCDIFF 通用差分和压缩数据格式
    • RFC2118 Microsoft 点对点压缩 (MPPC) 协议

    我可能忽略了其他相关的 RFC。

    【讨论】:

      【解决方案3】:

      这是 Rick 出色回答的后续行动,我对此表示赞同。很遗憾,我无法在评论中添加图片。

      我遇到了这个问题,并决定尝试对 500 条大小从 6 到 340 字节不等的 ASCII 消息样本进行压缩。每条消息都是由环境监测系统生成的一小段数据,通过昂贵的(按字节付费)卫星链路进行传输。

      最有趣的观察是,压缩后消息更小的交叉点与生命、宇宙和万物的终极问题相同:42字节。

      要在您自己的数据上尝试一下,这里有一点 node.js 的帮助:

      const zlib = require('zlib')
      const sprintf = require('sprintf-js').sprintf
      const inflate_len = data_packet.length
      const deflate_len = zlib.deflateRawSync(data_packet).length
      const delta = +((inflate_len - deflate_len)/-inflate_len * 100).toFixed(0)
      console.log(`inflated,deflated,delta(%)`)
      console.log(sprintf(`%03i,%03i,%3i`, inflate_len, deflate_len, delta))
      

      【讨论】:

        【解决方案4】:

        所有这些算法都值得尝试。正如您所说,它们并未针对小文件进行优化,但您的下一步就是简单地尝试它们。测试压缩一些典型数据包并查看结果大小可能只需要 10 分钟。 (也尝试不同的压缩标志)。从生成的文件中,您可能会挑选出最有效的工具。

        您列出的候选人都是不错的第一次尝试。你也可以试试 bzip2。

        当测试很容易进行时,有时简单的“全部尝试”是一个很好的解决方案。想太多有时会减慢你的速度。

        【讨论】:

        • 我同意,并要求您在完成后发布结果:)
        【解决方案5】:

        我认为文件大小并不重要 - 如果我没记错的话,GIF 中的 LZW 每 4K 重置一次它的字典。

        【讨论】:

          【解决方案6】:

          ZLIB 应该没问题。在 MCCP 中使用。

          但是,如果您真的需要良好的压缩,我会分析常见模式并在客户端中包含它们的字典,这样可以产生更高级别的压缩。

          【讨论】:

            【解决方案7】:

            我很幸运地直接使用了 zlib 压缩库,而不是使用任何文件容器。 ZIP、RAR 有存储文件名等内容的开销。我已经看到这种压缩方式对小至 200 字节的数据包产生了积极的结果(压缩小于原始大小)。

            【讨论】:

              【解决方案8】:

              您可以测试bicom。 该算法禁止用于商业用途。 如果您希望它用于专业或商业用途,请查看“范围编码算法”。

              【讨论】:

                【解决方案9】:

                你可以试试delta compression。压缩将取决于您的数据。如果您对有效负载进行了任何封装,则可以压缩标头。

                【讨论】:

                  【解决方案10】:

                  我按照世田谷亚诺在回答中的建议做了:做了一些样本测试并比较了结果。

                  压缩测试使用 5 个文件完成,每个文件大小为 4096 字节。这5个文件中的每个字节都是随机生成的。

                  重要提示:在现实生活中,数据不可能全是随机的,但往往会有一些安静的重复字节。因此,在实际应用中,压缩比以下结果要好一些。

                  注意:这 5 个文件中的每一个都是单独压缩的(即不与其他 4 个文件一起压缩,这样压缩效果会更好)。在下面的结果中,为了简单起见,我只使用了 5 个文件大小的总和。

                  我包含 RAR 只是为了比较,即使它不是开源的。

                  结果:(从最好到最差)

                  LZOP:20775 / 20480 * 100 = 原始大小的 101.44%

                  RAR : 20825 / 20480 * 100 = 原始大小的 101.68%

                  LZMA:20827 / 20480 * 100 = 原始大小的 101.69%

                  ZIP : 21020 / 20480 * 100 = 原始大小的 102.64%

                  BZIP:22899 / 20480 * 100 = 原始大小的 111.81%

                  结论:令我惊讶的是,所有经过测试的算法都产生了比原始算法更大的尺寸!!!我猜它们只适用于压缩较大的文件,或者有很多重复字节的文件(不是像上面那样的随机数据)。因此,我不会对我的 TCP 数据包使用任何类型的压缩。也许这些信息对考虑压缩小块数据的其他人有用。

                  编辑: 我忘了提到我对每个算法都使用了默认选项(标志)。

                  【讨论】:

                  • 你的测试毫无价值。几乎任何压缩算法都会阻塞随机数据——事实上,压缩率是一个有用的测试数据块的随机程度——如果“压缩”扩大数据,它可能是高熵的。用真实数据再试一次,你可能会得到有用的结果。
                  • 我同意测试毫无价值。随机分布的数据不会被压缩,实际上大多数压缩算法的基础是数据不是随机的。此外,您的比较不包括 zlib,当使用 STORE 而不是 DEFLATE 时,它每 64k 只添加 5 个字节。
                  • 压缩不是魔术。它通过观察重复模式来工作。随机数据没有重复模式,因此不会压缩。它不能,因为 8^4096 > 8^4095。
                  • 这里所有的 cmets 都朝着同一个方向发展:压缩“随机噪声”是没有意义的。压缩工作因为数据不是随机的。如果你想要一个有效的测试,最好使用真实的数据包。
                  最近更新 更多