GZIP或DEFLATE最多可以增加文件大小多少?

12

众所周知,GZIP或DEFLATE(或任何压缩机制)有时可以增加文件大小。那么文件增大的最大百分比或常数是多少?

如果一个文件大小为X字节,并且我将对其进行gzip压缩,并且需要提前预算文件空间,那么最坏情况是什么?

更新:有两个开销:GZIP添加标头,通常为18个字节,但实际上可以任意长。那DEFLATE呢?它可以通过乘法因子扩展内容,其乘法因子未知。是否有人知道这个值是多少?


1
我想这将把每个字节编码为一个文字。可能会增加2倍左右的大小。你可以在压缩流前面加上一个布尔值,指示它是否实际上被gzip压缩了。这允许你将最大空间限制在一个额外的字节内。 - usr
关于额外的18个字节:Mark在这里解释了(http://stackoverflow.com/a/38148423/43615)。其中10个字节是最短的gzip头(没有文件名),另外8个字节是用于校验和原始文件长度低4个字节的常量尾部。 - Thomas Tempelmann
2个回答

11

gzip会加上至少18个字节的头部和尾部。头部还可以包含路径名称,这将添加相同数量的字节加上一个结尾零。

Gzip中的deflate实现有一个选项,每个块可以存储16383个字节,开销为五个字节。如果选择其他方式需要更多字节,则它将始终选择此选项。因此,对于n个输入字节,最大压缩字节数为:

n+5(floor(n/16383)+1)


使用您的公式,我经常在已压缩的数据(例如视频)上使用deflate()时返回avail_out==0。这不应该发生,对吧?在调用之前,avail_in为10485760,avail_out为10488965,即多3205个。使用zlib v1.2.5(OSX 10.10.5上的默认值),压缩级别9,策略0,wbits -15。 - Thomas Tempelmann
没关系,我已经想通了:如果输出恰好是马克公式中给出的最大值,那么avail_out==0将变成零,但这仍然意味着它成功了,没有必要循环回去并提供另一个缓冲区。然而,为了安全地告知这种状态,最好在输出缓冲区中再添加一个字节,这样当deflate生成最大输出大小时,仍会在缓冲区中留下一个字节——这样,对avail_out==0的检查永远不会触发,如果会触发,那就清楚地表明出了问题。 - Thomas Tempelmann

0

压缩文件总是有一个头部,指示如何解压它们。

该头部的大小表示在压缩无法压缩的文件(因为数据没有顺序/模式,是随机的)时的最坏情况开销。

头部根据具体算法而异,也可能包含可变长度的信息,例如存档中的文件列表。

GZip至少有18个字节的开销(头部+页脚中的CRC-32),并且可以选择包含存档中的文件列表。

http://en.wikipedia.org/wiki/Gzip#File_format

请注意,在特殊情况下,自定义压缩算法可以减少或消除头部开销。例如,我曾经使用过一个由压缩和解压软件知道的自定义压缩字典来压缩短文本,因此不需要头部。这是一个相当罕见的用例,可能在大多数情况下并不有用(考虑到存储和带宽相对便宜)。

1
GZIP 中的块也可以更长 - 因此,除了 +18 之外,还有一些比例因子。不过我不确定它是什么。 - SRobertJames
这可能是维基百科文章中提到的一种可选标头之一。并不是每个GZIP实现都有必要包含它(除非该文章是错误的)。 - Eric J.

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