确定性地压缩 .tar.gz 文件

确定性地压缩 .tar.gz 文件

我想对压缩文件执行一系列重新压缩来研究它们的属性。

起初,我尝试简单地.zip在循环中重新压缩文件:

for f in $(seq 1 100)
do 
  zip $f.zip -9 -v $(($f-1)).zip
done

从一个固定0.zip文件开始,我注意到,如果我重新运行这些行,除了前几个文件之外,其他所有文件的大小都不同。经过一番调查,我意识到这是由压缩文件的时间戳引起的。然后我在重新压缩之前重置了时间戳:

for f in $(seq 1 100)
do
  touch $(($f-1)).zip -t 200101010101
  zip $f.zip -9 -v $(($f-1)).zip
done

这次我使用 获得了压缩的确定性结果zip。但是,使用tar算法 gzip仍然不起作用。每次我运行:

for f in $(seq 1 100)
do
  touch $(($f-1)).tar.gz -t 200101010101
  tar cvfz $f.tar.gz $(($f-1)).tar.gz
done

我得到的文件大小各不相同,从4.tar.gz100.tar.gz。为什么会发生这种情况?我该怎么做才能防止这种情况发生?

答案1

好的,所以我认为我终于找到了一种按照我想要的方式获得东西的方法,它涉及分别使用targzip(我使用两个 GNU 工具,tar 1.26 和 gzip 1.6)。

当使用z中的选项时tar,它首先创建 tar 文件,然后立即使用时间戳来创建 gzip 文件。换句话说,我无法控制中间文件的时间戳(除了更改要存档的原始文件的 mtime 之外,我没有找到任何选项来做到这一点),因此 .tar.gz 文件最终是不确定的。

但是,如果我首先使用不带 gzip 的 tar,然后修改 tar 文件的时间戳(touch例如使用),然后使用 gzip 进行编译,我就会得到确定的结果。

顺便说一句,使用两步过程生成的文件要小得多(在我的示例中约为 400KB,而使用带 z 选项的 tar 时约为 1.2MB)。这一定与单独使用 tar+gzip 和 gzip 时的默认设置有关。由于我的原始文件本来就是空的,我不确定大小减少是否有意义。

无论如何,我的问题的简短答案是:

  • 可以获得确定性结果,但需要分别使用 tar 和 gzip;

  • 使用 时似乎无法获得确定性结果tar -z,因为 gzip 压缩之前的中间 tar 文件的时间戳。此时间戳不受用户控制。

答案2

为了能够使用 tar 进行增量备份,某些版本的 tar 会存储文件添加到存档的时间。这可能会导致每次运行测试时输出不同,因此结果似乎不确定。

答案3

正如您所提到的,您需要分别执行 tar 和 gzip 步骤,但是您不需要中间文件,您只需将输入从 tar 传输到 gzip 并在 gzip 中指定 -n 选项即可。从手册页中:此选项会阻止将文件名和时间戳存储在输出文件中。

tar cvf - /path/to/files | gzip -n > archive.tar.gz

在不同时间对同一组文件运行上述命令两次并检查 md5 值。您应该看到两个档案完全相同。

相关内容