我想对压缩文件执行一系列重新压缩来研究它们的属性。
起初,我尝试简单地.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.gz
到100.tar.gz
。为什么会发生这种情况?我该怎么做才能防止这种情况发生?
答案1
好的,所以我认为我终于找到了一种按照我想要的方式获得东西的方法,它涉及分别使用tar
和gzip
(我使用两个 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 值。您应该看到两个档案完全相同。