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

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

假设我有 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 的未解释空间。

答案1

Zip 在压缩时会分别处理每个文件的内容。每个文件都有自己的压缩流。压缩算法中支持该功能(通常放气) 来识别重复的部分。但是,Zip 不支持查找文件之间的冗余。

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

答案2

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

简而言之,如果您压缩一个文件,则将(短)代码映射到(较长)模式的字典必然包含在每个生成的 zip 文件中;如果您压缩一个长文件,则该字典将被“重复使用”,并且在所有内容中变得更加有效。

如果您的文件有一点相似(文本总是如此),那么重新使用“字典”就会变得非常有效,并且结果是总 zip 文件要小得多。

答案3

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

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

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

答案4

OP 遗漏的一个选项是将所有文件一起压缩并关闭压缩,然后将压缩设置为最大。这大致模拟了 *nix .tar.Z、.tar.gz、.tar.bz 等压缩档案的行为,允许压缩利用跨文件边界的冗余(ZIP 算法在单次运行中无法做到这一点)。这允许稍后提取单个 XML 文件,但最大化压缩。缺点是提取过程需要额外的步骤,暂时使用比普通 .zip 所需的多得多的磁盘空间。

随着 7-Zip 等免费工具的普及,tar 系列扩展到 Windows,真的没有理由不使用 .tar.gz 或 .tar.bz 等,因为 Linux、OS X 和 BSD 都有本机工具来操作它们。

相关内容