在Ruby中压缩大字符串

25
我有一个 Web 应用程序(Ruby on Rails),它将一些 YAML 作为隐藏输入字段的值发送。现在我想要减小发送到浏览器的文本大小。什么是最有效的无损压缩形式,可以发送最少的数据?我可以承担服务器端压缩和解压缩的额外成本。
2个回答

66

你可以使用 Ruby 核心中的 zlib 实现来压缩/解压数据:

require "zlib"
data = "some long yaml string" * 100
compressed_data = Zlib::Deflate.deflate(data)
#=> "x\x9C+\xCE\xCFMU\xC8\xC9\xCFKW\xA8L\xCC\xCDQ(.)\xCA\xCCK/\x1E\x15\x1C\x15\x1C\x15\x1C\x15\x1C\x15\x1C\x15\x1C\x15\x1C\x15D\x15\x04\x00\xB3G%\xA6"

您应该对压缩数据进行Base64编码,以使其可打印:

require 'base64'
encoded_data = Base64.encode64 compressed_data
#=> "eJwrzs9NVcjJz0tXqEzMzVEoLinKzEsvHhUcFRwVHBUcFRwVHBUcFUQVBACz\nRyWm\n"

接下来,在客户端,您可以使用pako(一个将zlib移植到JavaScript的库)来获取您的数据。 这个答案可能有助于您实现JS部分。

为了让您了解其有效性,以下是示例字符串的大小:

data.size            # 2100
compressed_data.size #   48
encoded_data.size    #   66

在客户端进行压缩并在服务器端进行解压缩时,同样的原理也适用。

Zlib::Inflate.inflate(Base64.decode64(encoded_data))
#=> "some long yaml stringsome long yaml str ... (shortened, as the string is long :)

免责声明:

  • 红宝石zlib实现应与pako实现兼容。但我没有尝试过。
  • 关于字符串大小的数字有点欺骗性。这里的Zlib非常有效,因为字符串经常大量重复。真实数据通常不会重复那么多。

3
好像我几天前不小心点了踩,但我不记得自己这么做了。如果可以的话,请编辑一下,让我取消这个意外的踩赞 :( - Krule
4
@Krule,谢谢你的友善。开始时我不确定能否找到有用的更新,但后来我偶然发现了pako库,它似乎比zlib更好用。所以感谢你提醒我再次查看我的答案,我实际上可以改进它 :) - tessi
7
请注意,Zlib::Deflate.deflate 方法的输出格式与 gzip 命令行工具生成的格式不兼容,因此 gunzip 不会接受它。gunzip 希望在压缩内容之前包含一些头数据。如果您想使用 gunzip 读取输出,则可以使用以下代码:Zlib::Deflate.new(nil, 31).deflate(data, Zlib::FINISH) - Guss
1
这非常高效,因为示例数据集多次复制测试,而在其他示例中则不太高效。 - Ian Vaughan

0
如果您正在开发Rails应用程序,您还可以使用ActiveSupport::Gzip包装器,它允许对字符串进行gzip压缩/解压缩。
compressed_log = ActiveSupport::Gzip.compress('large string')
=> "\x1F\x8B\b\x00yq5c\x00\x03..."

original_log = ActiveSupport::Gzip.decompress(compressed_log)
=> "large string"

在幕后,压缩方法使用 Zlib::GzipWriter 类来写入 gzip 文件。同样地,解压方法使用 Zlib::GzipReader 类来读取 gzip 文件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接