如何将两个或多个gzip文件/流合并

15

我想将两个或多个gzip流连接起来,而不需要重新压缩它们。

我的意思是,我将A压缩为A.gz,将B压缩为B.gz,我想使用C或C++将它们压缩为单个gzip (A+B).gz,而不需要再次压缩。

几点说明:

  • 即使你只是连接两个文件,gunzip也可以处理它们,但大多数程序可能无法处理两个块。
  • 我曾经看过一种代码示例,它只通过解压缩文件并操作原始文件就能实现此功能,这比普通的重新压缩快得多,但仍需要O(n)的CPU操作。
  • 不幸的是,我找不到我曾经找到的这个例子(仅使用解压缩进行连接),如果有人能指出来,我将不胜感激。

注意:这不是此问题的重复,因为提出的解决方案不符合我的需求。

澄清编辑:

我希望将几个压缩的 HTML 片段连接在一起,并将它们作为一个页面发送到浏览器,根据请求:"Accept-Encoding: gzip",响应为:"Content-Encoding: gzip"

如果流像cat a.gz b.gz >ab.gz那样简单地连接,Gecko (firefox) 和 KHTML 网页引擎只会得到第一部分(a);IE6 不显示任何内容,而 Google Chrome 正确显示第一部分(a),第二部分(b)则显示垃圾字符(根本没有解压缩)。

只有 Opera 能够很好地处理这个问题。

因此,我需要创建一个由多个块组成的单个gzip流,并在不重新压缩的情况下发送它们。

更新:我在zlib的示例中找到了gzjoin.c,它只使用解压缩来实现。问题是解压缩仍然比简单的memcpy慢。

它仍然比最快的gzip压缩快4倍。但这还不够。

我需要找到需要与gzip文件一起保存的数据,以便不运行解压缩过程,并且如何在压缩期间找到此数据。


你真的想要压缩它们,还是只是将它们连接到同一个文件中? - Tobias Wärre
我想创建一个gzip压缩的文件/流/内存块,其中包含两个其他gzip压缩的文件/流/内存块,而无需对它们进行解压、连接和再次压缩。 - Artyom
请提供需要翻译的英文内容。 - Artyom
gzjoin.c需要解压第二个流以与流保持同步。由于zlib流不包含索引,因此需要这样做。理论上,您可以在提前gzip时添加索引,并修改gzjoin以使用此索引。但这并不是一件容易的事情... - Rutger Nijlunsing
如果您将此作为答案编写,我将能够接受它。 - Artyom
4个回答

15

参考RFC1951RFC1952,该格式由多个成员组成,每个成员包含头部、数据和尾部三个部分。数据本身也是由头部和数据两个部分构成的块集合。

为了模拟将两个或多个文件级联后进行gzip压缩的效果,只需正确调整各个头部(例如最后一个块标志)和尾部,并复制数据部分。

问题在于,尾部有未压缩数据的CRC32校验和,不确定在已知各部分的CRC时是否容易计算该值。

编辑:您找到的gzjoin.c文件中的注释暗示,虽然可以在不解压缩数据的情况下计算CRC32,但还有其他需要解压缩的操作。


1
如果您有分片的CRC,则可以使用它们来计算最终的CRC。如果我没有弄错的话,如果您有带有Crc1的Msg1和带有Crc2的Msg2,则要计算[Msg1,Msg2]的CRC,您可以计算[Crc1,0,0,0,0…(零Msg2长度次)]的CRC并将其与Crc2异或。也许某处需要一补数,但这就是想法。 - eugensk

6
gzip手册表示,两个gzip文件可以像您尝试的那样连接起来。

http://www.gnu.org/software/gzip/manual/gzip.html#Advanced-usage

看起来其他工具可能存在问题。如此在这个错误报告中所见。 http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=97263

除了向每个浏览器制造商提交错误报告并希望他们遵守外,也许您的程序可以缓存所需数据的最常见连接。

正如其他人所提到的,您可能能够进行手术: http://www.gzip.org/zlib/rfc-gzip.html

这需要对最终未压缩文件进行CRC-32。通过添加各个子文件的长度可以轻松计算未压缩文件的所需大小。

在最后一个链接的底部,有用于计算命名为update_crc的运行crc-32的代码。

每次运行进程时在未压缩的文件上计算CRC可能比gzip算法本身更便宜。


说到.NET库,我个人验证过这个库支持多部分GZip文件: http://www.icsharpcode.net/opensource/sharpziplib/ - DenNukem

3
似乎个别文件的原始压缩是由您完成的。同时,所需结果(多个部分的串联)足够小,可以在一个页面中发送到Web浏览器。在这种情况下,您的效率担忧似乎是没有必要的。 请注意:(1)gzjoin.c方法很可能是您根据所述问题得到的最佳答案。(2)它是由gzip创始人之一进行的复杂微型手术,并可能未经过广泛的应力测试。
请考虑一种无聊易懂可靠的方法:存储原始片段未压缩,然后选择所需片段,将它们连接并压缩。请注意,压缩比可能会优于将小的压缩片段粘合在一起所获得的压缩比。

是的,我是这两个块的创始人,所以我甚至可以保存一些元数据或做出一些假设。因此,我知道gzjoin是最简单和最不容易出错的方法,但它仍然只比简单的“gzip -1”快4倍。我需要接近memcpy的加速。我的想法是:我会缓存一些准备好的块,并根据用户请求将它们组合起来。 - Artyom
你还没有解释为什么需要“memcpy近速增”在看起来是相对较小的数据量上。也许你可以告诉我们每秒需要服务多少个这样的页面以及它们有多大。 - John Machin
假设页面和块很大,负载非常高。 - Artyom

1
如果打包它们不是不可能的选择(因为链接的{{link1:cat解决方案}}对您来说不可行):
tar cf A_B.gz.tar A.gz B.gz

然后,要将它们取回:

tar xf A_B.gz.tar

不,我根本没有谈论tar。 - Artyom
1
我现在明白你的意思了……你想要做到“gunzip A.gz&gunzip B.gz&cat A B> C&gzip C.gz A B”的等效操作,但不进行解压缩,希望能够实现O(1)的处理时间。gzip不能做到这一点,我也不知道是否有可以的工具。但即使有,它仍然需要O(n)的时间,因为它至少需要检查压缩文件以确定如何压缩它们。 - Mark Jones
把它们打包成tar文件有什么问题,这样可以实现你想要做的一切。 - Martin York
显然他的代码无法处理两个gzip压缩文件。他想将这两个文件合并成一个gzip压缩文件,而不需要解压缩这两个原始文件。 - Mark Jones
“把它们打包有什么问题”——如果和我尝试的类似,数据需要被压缩。 - Wade

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