我有几百个.tar.xz
几乎相同的文件(它们是日常数据库转储,并且数据库变化缓慢)。
我相信,由于未压缩文件的相似性,它们会压缩得很好,并且小规模测试表明,压缩任意数量的这些未压缩文件会创建一个仅比其中一个稍大的存档。
我的问题是,所有未压缩的文件都会有几 TB(压缩比约为 25:1),而且我没有那么多磁盘空间可用作工作区。
有没有一种方法可以一次处理一个单独的压缩文件,将它们添加到单个存档中并保留将它们压缩在一起的好处?
答案1
由于 tar 文件是一种流格式 - 您可以将cat
其中两个文件放在一起并获得几乎正确的结果 - 您根本不需要将它们提取到磁盘来执行此操作。您可以(仅)解压缩文件,将它们连接在一起,然后重新压缩该流:
xzcat *.tar.xz | xz -c > combined.tar.xz
combined.tar.xz
将是组件 tarball 中所有文件的压缩 tarball,仅略有损坏。要提取,您必须使用--ignore-zeros
选项(在 GNU 中tar
),因为档案确实有一个“文件结束”标记,它将出现在结果的中间。但除此之外,一切都会正常工作。
GNUtar
还支持--concatenate
产生组合档案的模式。它具有与上面相同的限制 - 您必须使用它--ignore-zeros
来提取 - 但它不适用于压缩档案。您可以构建一些东西来欺骗它使用进程替换来工作,但这很麻烦,甚至更脆弱。
如果有些文件在不同的 tar 文件中出现多次,则这将无法正常工作,但无论如何您都会遇到这个问题。否则,这将给你你想要的东西——管道输出xz
就是tar
压缩其输出的方式。
如果仅适用于特定tar
实现的档案不足以满足您的目的,那么r
您可以将以下内容附加到档案:
tar cJf combined.tar.xz dummy-file
for x in db-*.tar.xz
do
mkdir tmp
pushd tmp
tar xJf "../$x"
tar rJf ../combined.tar.xz .
popd
rm -r tmp
done
一次只能提取一个存档,因此工作空间仅限于单个存档内容的大小。压缩是流式传输的,就像您一次性制作最终存档一样,因此它会像以前一样好。您进行了大量的过度解压缩和重新压缩,这将使其比版本慢cat
,但生成的存档将在任何地方工作,无需任何特殊支持。
请注意,根据您的具体需求,只需将未压缩的 tar 文件本身添加到存档中就足够了。它们将(几乎)完全压缩单个文件中的内容,并且会减少每个文件的压缩开销。这看起来像:
tar cJf combined.tar.xz dummy-file
for x in db-*.tar.xz
do
xz -dk "$x"
tar rJf combined.tar.xz "${x%.xz}"
rm -f "${x%.xz}"
done
就最终压缩大小而言,效率稍低,因为流中存在额外的 tar 标头,但在提取所有文件并将其重新添加为文件时节省了一些时间。您最终会combined.tar.xz
包含许多(未压缩的)db-*.tar
文件。