在 Ruby 中压缩 Gzip 字符串

Posted

技术标签:

【中文标题】在 Ruby 中压缩 Gzip 字符串【英文标题】:Compress Gzip string in Ruby 【发布时间】:2012-12-27 17:33:05 【问题描述】:

我将如何编写一种方法来压缩不包含头文件的 Gzip 字符串,并将其压缩到我解压缩它之前的状态。原始压缩是在 C# 中完成的,我在 Ruby 中使用以下方法进行膨胀:

编辑:基本上,我想要匹配的 deflate 方法到这个膨胀:

def inflate(string)
    zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
    buf = zstream.inflate(string)
    zstream.finish
    zstream.close
    buf
end

解压前的字符串为:

"5\x891\n\xC30\x10\x04\xBDb\xEB\xE0F&\x81\xA4\xCA3\xDC\xA81\xD2\x1A]\xA1\x13\xB1.\x100\xFEF\xDE\e\x19\x9Cb\x99Yf\xCA\xB3A\x1A,\x13\xB1\x96R\x15I\x96\x85+5\x12\xA2=\xF4:\xAFb\xB9\xD0$\xA2\xF1\xF5>\xDA\xD3\xB9\x9A\xA8f\xFC\xD8\xE6\xFD\x00\x7F\xEB\f!Uk\xCF,\x91\xDC\x1C\x10J\xC4\xF7z\xCA\xE8p9\xF8\xFF\xF7\x93\xDEw\xD9\x7F"

而使用inflate解压后就是:

    "What is the common difference in this arithmetic sequence?\n\n\\indenttext11, 15, 19,\\dots\n\n\\emcee\n  \\mc \x964\n  \\mc 2\n *\\mc 4\n  \\mc 8\n  \\mc 11\n  "

我尝试创建多个 deflate 方法,但没有一个可以将其恢复为原始方法。感谢您的帮助!

编辑:原始压缩是在 .NET 2.0 中使用以下方法完成的

byte[] compressedStringBytes = CompressGzipString(String);

而 CompressGzipString 确实如此:

MemoryStream compressed = new MemoryStream();
DeflaterOutputStream zosCompressed = new DeflaterOutputStream(compressed, new Deflater(Deflater.BEST_COMPRESSION, true));
zosCompressed.Write(data, 0, data.Length);

如果无法将其还原为确切的原件,那么最标准化的压缩是什么,我的意思是一般性,并且能够以与原件相同的方式解压缩?

【问题讨论】:

你能解释一下它是如何在 C# 中被压缩的吗? 是的,有关该信息,请参阅原始帖子! 这看起来像 Java 代码,而不是 C#。 @Hyung:使用的对象 - CompressGzipStringDeflator - 不是标准 .NET 库的一部分。他们是从哪里来的? 发现错误。在“解压缩字符串之前”中的 \xB9 和 \x9A 之间缺少空格。您一定是无意中删除了它。加上空格后,“解压后”则匹配解压后的结果。 【参考方案1】:

这取决于它在 C# 中是如何被压缩的;在 .NET 4.5 之前,C# 中的 System.IO.DeflateStream/GZipStream 类使用了与 zlib 显着不同的 Microsoft 实现的 DEFLATE(这意味着您可能无法使用 zlib 轻松模拟它)。在几乎所有情况下都更糟,所以在 .NET 4.5 中,他们用 zlib 替换它

如果您知道生成字符串的 C# 版本,您可以确定是否可以返回原始字节。如果它是使用 .NET 4.5 生成的,您应该能够使用相同的设置进行标准放气以获得相同的字节。

【讨论】:

【参考方案2】:

不同的压缩器,相同压缩器的不同版本,或具有不同设置的相同压缩器的相同版本,即使它们都使用相同的压缩数据格式(例如 deflate )。唯一可以保证的是,当您解压缩时,您会得到与开始时完全相同的东西。事实上,这就是您真正需要的保证。为什么要完全相同的压缩流?

正如 Ron Warholic 所指出的,您甚至不会想要从 .NET 4.5 之前的损坏的 deflate 实现中恢复相同的压缩输出。由于 .NET 2.0 使用了自己独特的、损坏的、deflate 实现,因此您无法使用使用 zlib 的 ruby​​ 复制它。

正如 Ron Warholic 所指出的,ruby 和 .NET 4.5 或更高版本都使用 zlib,因此两者都应该使用相同的压缩级别产生相同的压缩输出。虽然这不能永远保证,因为新版本的 zlib 可能会产生不同的输出,而 ruby​​ 或 .NET 中的一个可能会更新到它,而另一个不会。同样如下所述,您无法直接控制 .NET 类的压缩级别。

如果无法将其还原为原始版本,那将是什么 最标准化的压缩,我的意思是一般压缩 将能够以与原始文件相同的方式解压缩 是吗?

无损压缩和解压缩的任何正确实现都将具有此属性。无论压缩数据可能有何不同,您都将始终返回到确切的原始数据。没有“最标准化的压缩”。

您的Zlib::Inflate.new(-Zlib::MAX_WBITS) 期待一个原始的放气流,没有标头或尾标。所以你需要在 C# 端生成它。

从.NET documentation 中并不清楚DeflateStream 类是压缩成 deflate 格式还是 zlib 格式(后者是带有 zlib 包装器的 deflate 格式,由两个前缀字节和四个后缀字节组成数据完整性检查)。如果它压缩为 deflate 格式,那么它将与您的Zlib::Inflate.new(-Zlib::MAX_WBITS) 兼容。如果它压缩为 zlib 格式,那么它将与Zlib::Inflate.new(Zlib::MAX_WBITS) 兼容(即没有减号)。或者,您可以删除前两个字节和后四个字节以返回放气流。

.NET 中的DeflateStream 类有点奇怪,因为它的CompressionLevel 是一个只有三个选项的enum,而不是 zlib (0..9) 提供的十个级别。这三个选项是OptimalFastestNoCompression。最后一个必须是0,第一个可能是9,中间一个可能是1或3。无论如何,默认压缩级别是没有选项的!该级别 (6) 在压缩与时间之间取得了很好的平衡。

您可能要考虑改用DotNetZip。它提供了一个完整的 zlib 接口,以便您可以准确地指定您想要做什么,并知道会发生什么。

【讨论】:

感谢您的澄清。你是对的,无论如何我都不想要相同的压缩流!但是,我仍然想知道我发布的内容的等效方法,因为我不确定如何使用“-Zlib::MAX_WBITS”的匹配选项进行放气。如果你能告诉我,那就太好了。

以上是关于在 Ruby 中压缩 Gzip 字符串的主要内容,如果未能解决你的问题,请参考以下文章

linux中压缩解压缩命令

如何在 Laravel 项目中压缩文件夹

如何在 Android 中压缩字符串

如何在 C# 中压缩(和解压缩)字节 []?

如何在 Objective C 中压缩、解压缩文件(arm64 支持)

如何从流/渲染字典中压缩 html 文件?