为什么Zip能够压缩单个文件比具有相同内容的多个文件小?


126

假设我有10,000个XML文件。现在假设我想将它们发送给朋友。在发送它们之前,我想对其进行压缩。

方法1:不要压缩它们

结果:

Resulting Size: 62 MB
Percent of initial size: 100%

方法2:压缩每个文件并将其发送给他10,000个xml文件

命令:

for x in $(ls -1) ;  do   echo $x ; zip "$x.zip" $x ; done

结果:

Resulting Size: 13 MB
Percent of initial size: 20%

方法3:创建一个包含10,000个xml文件的单个zip

命令:

zip all.zip $(ls -1)

结果:

Resulting Size: 12 MB
Percent of initial size: 19%

方法4:将文件串联成单个文件并压缩

命令:

cat *.xml > oneFile.txt ; zip oneFile.zip oneFile.txt

结果:

Resulting Size: 2 MB
Percent of initial size: 3%

问题:

  • 当我仅压缩单个文件时,为什么会得到如此显着更好的结果?
  • 我期望使用方法3会比使用方法2获得更好的结果,但事实并非如此。为什么?
  • 此行为特定于zip吗?如果尝试使用,gzip会得到不同的结果吗?

附加信息:

$ zip --version
Copyright (c) 1990-2008 Info-ZIP - Type 'zip "-L"' for software license.
This is Zip 3.0 (July 5th 2008), by Info-ZIP.
Currently maintained by E. Gordon.  Please send bug reports to
the authors using the web page at www.info-zip.org; see README for details.

Latest sources and executables are at ftp://ftp.info-zip.org/pub/infozip,
as of above date; see http://www.info-zip.org/ for other sites.

Compiled with gcc 4.4.4 20100525 (Red Hat 4.4.4-5) for Unix (Linux ELF) on Nov 11 2010.

Zip special compilation options:
    USE_EF_UT_TIME       (store Universal Time)
    SYMLINK_SUPPORT      (symbolic links supported)
    LARGE_FILE_SUPPORT   (can read and write large files on file system)
    ZIP64_SUPPORT        (use Zip64 to store large files in archives)
    UNICODE_SUPPORT      (store and read UTF-8 Unicode paths)
    STORE_UNIX_UIDs_GIDs (store UID/GID sizes/values using new extra field)
    UIDGID_NOT_16BIT     (old Unix 16-bit UID/GID extra field not used)
    [encryption, version 2.91 of 05 Jan 2007] (modified for Zip 3)

编辑:元数据

一个答案表明区别在于存储在zip中的系统元数据。我认为情况并非如此。为了测试,我做了以下工作:

for x in $(seq 10000) ; do touch $x ; done
zip allZip $(ls -1)

生成的zip文件为1.4MB。这意味着仍有约10 MB的无法解释的空间。


34
如果我没记错的话,正是这种现象引起人们的兴趣,.tar.gz而不是仅仅压缩整个目录。
corsiKa 2015年

18
一个类似的问题已经被问,TL;医生使用固体7zip的档案。
德米特里·格里戈里耶夫

3
@sixtyfootersdude作为验证某些答案的测试,您可以尝试压缩方法3中生成的拉链吗?我怀疑这会将文件大小减小到与方法4相当的大小
Travis

7
代替的$(ls -1)只是使用*for x in *; zip all.zip *
muru

4
如果要使用ZIP进行整体压缩,请采取以下解决方法:首先,创建一个包含所有文件的未压缩 ZIP。然后,将该ZIP放入另一个压缩的ZIP中。
user20574

Answers:


129

压缩时,Zip分别处理每个文件的内容。每个文件将具有其自己的压缩流。压缩算法(通常为DEFLATE)内支持识别重复部分。但是,Zip中不支持在文件之间查找冗余。

这就是为什么当内容位于多个文件中时会有太多额外空间的原因:它将相同的压缩流多次放入文件中。


9
这也是为什么某些压缩工具为您提供了单独或作为单个实体压缩文件的选项。(尽管通常这也意味着,如果您只想查看其中的单个文件,则必须解压缩更多的存档。)
JAB 2015年

28
@JAB:诸如7z和rar的压缩工具使用术语“实体”存档将多个文件从头到尾打包到更大的压缩流中。对于像64MiB这样的中等大小的块,对单个文件的随机访问可能需要从其所在的压缩块开始对多达64MiB的数据进行解压缩。您可以在随机访问和查找跨文件冗余之间取得不错的平衡。7z可以使用更有效(但压缩速度较慢)的LZMA压缩方案,这是与zip相比的另一个优势。
彼得·科德斯

您是说there is no support in Zip to find redundancy between files在zip文件规范中吗?
sixtyfootersdude 2015年

6
@sixtyfootersdude许多压缩算法(例如DEFLATE)作为流运行。为了恢复足够的信息以解压缩一部分流,您需要处理整个流直到那时。如果他们试图找到文件之间的冗余,则必须解压缩所有1000个文件才能到达最后一个文件。实际上,这通常是tgz的工作方式。但是,zip旨在让您提取单个文件。TGZ被设计得更加全有或全无
科特阿蒙

1
@sixtyfootersdude-是的。解释一下Cort:pkzip规范不支持跨文件工作。如果他们这样做,则提取一个文件可能需要提取整个存档(以及每个文件)。
詹姆斯·斯内尔

48

ZIP压缩基于要压缩的数据中的重复模式,文件越长,压缩效果越好,因为可以找到并使用越来越多的模式。

简化后,如果压缩一个文件,则在每个结果zip文件中都必须包含将(短)代码映射到(较长)模式的字典。如果您压缩一个长文件,字典将被“重用”,并且在所有内容上都将变得更加有效。

如果您的文件甚至有点相似(就像文本一样),则对“字典”的重用将非常有效,结果总zip会小得多。


3
ZIP既可以存档也可以压缩。这是否意味着ZIP会分别压缩每个文件,即使它们最终都位于同一个ZIP文件中?
gerrit 2015年

2
那种必须-想象您删除了一个文件,您不想让它花费另外半个小时用新的“字典”重新压缩其余文件。-同样,它可能假设不同的文件需要非常不同的“字典”。
Aganju 2015年

2
我不明白为什么要这么做。使用Unix工具,我将首先使用tar归档文件,然后使用gzip / bz2 / lzma压缩文件。压缩算法并不关心存档中编码了多少文件。此外,从压缩档案中删除单个文件的确有多普遍?我认为我从未做到过。
gerrit

4
我不同意,这可能是一个好方法。我没有设计或编写ZIP。我只是说了它的作用……
Aganju 2015年

16
@gerrit它有其自身的问题。Zip旨在允许您快速访问存档中的任何文件-尝试从100 GiB UHA存档中解压缩单个文件,您将了解为什么他们选择这种方式。它还设计用于附加-您可以拥有备份zip,并仅根据需要不断添加(或替换)文件。使用存档时,所有这些都是巨大的帮助。折衷方案是,如果要压缩非常相似的文件(不是很常见),则无法利用相似性来减小归档文件的大小。
罗安2015年

43

在Zip中,每个文件分别压缩。相反的是“固体压缩”,即文件被压缩在一起。默认情况下,7-zip和Rar使用实体压缩。Gzip和Bzip2无法压缩多个文件,因此首先使用Tar,其效果与实体压缩相同。

由于xml文件具有相似的结构,并且如果将文件压缩在一起,则内容可能也相似,因此压缩率会更高。

例如,如果一个文件包含字符串"<content><element name=",并且压缩程序已经在另一个文件中找到该字符串,它将用一个指向先前匹配项的小指针替换该字符串,如果压缩程序不使用“固体压缩”,则字符串中的第一个出现文件将被记录为较大的文字。


9

Zip不仅存储文件的内容,还存储文件元数据,例如拥有的用户ID,权限,创建和修改时间等。如果您有一个文件,则有一组元数据;如果您有10,000个文件,则有10,000套元数据。


3
很好,但是系统元数据仅占用1.4MB的空间。看到我的编辑。
sixtyfootersdude

1
我不熟悉zip算法,但是元数据不仅是文件信息,而且还包括大小和字典之类的内容,可能还包括一些有关字符分布的信息。非空文本文件上的字典将为非零。这可能就是为什么您看到xml文件中的元数据大于空文件的原因。
本·理查兹

这是我的第一个想法。压缩文件头信息
WernerCD

此仅说明图2和3之间的差-不4.
Luaan

@Luaan不,在2和3中,所有10,000个文件的元数据都包含在一个或多个zip文件中,因此文件总大小几乎相同。在4中,只有一个文件的元数据,而zip文件要小得多。
Mike Scott

7

OP遗漏的一个选项是将所有文件压缩在一起,同时关闭压缩功能,然后将压缩结果设置为最大的压缩结果文件压缩。通过允许压缩利用跨文件边界的冗余,粗略地模拟了* nix .tar.Z,.tar.gz,.tar.bz等压缩档案的行为(ZIP算法在一次运行时无法做到)通过)。这样可以在以后提取单个XML文件,但可以最大程度地提高压缩率。缺点是提取过程需要额外的步骤,暂时占用了比普通.zip所需更多的磁盘空间。

借助7-Zip这样的免费工具将tar系列扩展到Windows,实际上没有理由不使用.tar.gz或.tar.bz等,因为Linux,OS X和BSD都具有操纵它们的本机工具。


gzip和bzip2可能会变得更糟,因为它们在设计时就考虑到了压缩流,因此它们将不得不开始输出压缩数据,甚至所有压缩数据都不得而知。
rackandboneman 2015年

@rackandboneman:这是压缩文件时要做出的权衡,该文件的大小大于压缩时愿意使用的内存量。(而且,找到全局最优值所需的CPU时间也将是巨大的。)巨大的压缩字典还可以增加解压缩所需的内存。这是LZMA(xz/ 7-zip)的选项。无论如何,自适应字典一旦可见就可以选择模式。并非只是基于前32k构建静态编码系统。这就是为什么gzip不烂的原因。
彼得·科德斯

如果您需要使用zip格式,我真的很喜欢这个“技巧”。我不同意您的“没有理由不使用7-zip”的信息-如果我要将文件发送给非技术朋友,我想确保他们能够轻松打开它。如果我要发送给业务客户,那就更是如此。
Wowfunhappy

5

zip压缩格式分别存储和压缩每个文件。它不利用文件之间的重复,而仅利用文件内的重复。

串联文件可以使zip利用所有文件的重复功能,从而大大提高压缩率。

例如,假设每个XML文件都有一个特定的头。该标头在每个文件中仅出现一次,但在许多其他文件中几乎相同地重复。在方法2和3中,zip无法为此压缩,但在方法4中,它可以压缩。


3
这与5小时前已发布的前3个答案之一有何不同?
Xen2050

1
@ Xen2050差别不大,我只是认为我可以更清楚地解释它。
BonsaiOak 2015年

1
@BonsaiOak-然后在正确答案中添加评论,或者如果您有足够的代表,则进行编辑。如果不是,但您的评论增加了清晰度,则其他人可能仍会选择并编辑帖子。
AdamV 2015年

@AdamV我明白你的意思。我的答案目前没有添加任何有用的信息,尽管可以说是我写的时候添加的。在第一个答案下已经有适当的注释,因此我也看不出添加它们的意义。您是说我应该结束我的回答吗?打开它有什么害处?
BonsaiOak 2015年

4

在Mike Scott提到的元数据旁边,压缩算法也有开销。

压缩一堆单独的小文件时,您必须非常幸运地能够压缩它们,因为恰好会填满一个压缩块。当压缩单个整体块时,系统可以继续将数据流式传输到其算法,而忽略单个文件的“边界”(由于缺少更好的单词)。

还已知ASCII具有高压缩系数。plus xml通常非常重复,使元数据成为数据的一大块,无法像xml内容那样容易地进行压缩。

最后,如果内存使用得当,则zip使用类似于字典编码的内容,由于重复性,它在ascii文件上尤其有效,在XML上尤其有效

数据压缩说明:http : //mattmahoney.net/dc/dce.html


3

考虑以下XML:

<root>
  <element id="1" />
  <element id="2" /> 
  <other id="3" />
  ...
</root>

XML具有非常重复的结构,Zip利用这些重复来构建其模式更多出现的字典,然后在压缩时使用较少的位来存储更多的重复模式,而使用更多的位来存储更少的重复模式

当你串连这些文件,源文件(来源ZIP)是很大的,但包含了许多重复的模式,因为XML的无聊结构德分布摊销在大整个文件,给人以ZIP来存储这些机会模式使用更少的位。

现在,如果将不同的XML组合到一个文件中,即使这些文件具有完全不同的标记名,压缩算法也将在所有文件中找到最佳的模式分布,而不是逐个文件。

最终,压缩算法找到了最佳的重复模式分布。


-1

除了7-Zip答案之外,还有另一种方法不那么好,但是如果出于某种原因您不想使用7-Zip,则值得进行测试:

压缩zip文件。现在,通常一个zip文件是不可压缩的,但是当它包含许多相同的文件时,压缩程序可以找到此冗余并将其压缩。请注意,在处理大量没有冗余的文件时,我也看到了很小的收获。如果您真的很在意大小,那么如果您的zip文件过多,则值得尝试。


如上文所述,只有在压缩关闭的情况下进行第一个压缩时,这种方法才有效。
蒙迪·哈德2015年

@MontyHarder我已经看到它在压缩打开的情况下可以工作。
罗伦·佩希特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.