立即打印存档文件列表(无需解压整个存档)

立即打印存档文件列表(无需解压整个存档)

档案的一个问题.tar.gz是,当我尝试列出档案的内容时,计算机实际上会对其进行解压缩,如果文件很大,这将需要很长时间。

其他文件格式如.7z.rar.zip则不存在此问题。列出它们的内容只需要一瞬间。

在我看来,这是.tar.gz存档格式的一个巨大缺点。

所以我实际上有两个问题:

  1. .tar.gz尽管有这个缺点, 为什么人们还是使用这么多?
  2. 如果我想要“即时内容列表”功能,我有哪些选择(我的意思是其他软件或工具)?

答案1

重要的是要理解这里存在一个权衡。

tar方法磁带归档器。在磁带上,您主要进行顺序读取和写入。如今,磁带已很少使用,但tar仍因其能够以流的形式读取和写入数据而被使用。

你可以做:

tar cf - files | gzip | ssh host 'cd dest && gunzip | tar xf -'

你不能用zip或类似的东西做到这一点。

zip如果不先将存档内容存储在本地可查找文件中,您甚至无法列出存档的内容。像:

curl -s https://github.com/dwp-forge/columns/archive/v.2016-02-27.zip | unzip -l /dev/stdin

行不通的。

要实现内容的快速阅读,zip或者类似的需要建立索引。该索引可以存储在文件的开头(在这种情况下,它只能写入常规文件,而不是流),也可以存储在文件的末尾,这意味着归档器需要在最后打印之前记住所有归档成员并且意味着被截断的存档可能无法恢复。

这也意味着存档成员需要单独压缩,这意味着压缩率要低得多,尤其是在有很多小文件的情况下。

类似格式的另一个缺点zip是归档与压缩相关,您无法选择压缩算法。了解如何tar使用compress( tar.Z)、然后使用gzip、然后bzip2、然后xz设计新的性能更高的压缩算法来压缩存档。加密也是如此。如今谁会相信zip的加密技术?

现在,档案的问题tar.gz并不在于需要解压缩它们。解压缩通常比读取磁盘更快(您可能会发现列出大型 tgz 存档的内容比列出未缓存在内存中的未压缩的相同内容更快),但您需要读取整个存档。

无法快速读取索引并不是真正的问题。如果您确实预见到需要经常读取存档的表内容,则可以将该列表存储在单独的文件中。例如,在创建时,您可以执行以下操作:

tar cvvf - dir 2> file.tar.xz.list | xz > file.tar.xz

IMO 的一个更大的问题是,由于存档的顺序方面,您无法在不读取存档的整个开头部分的情况下提取单个文件。 IOW,您不能在存档中进行随机读取。

现在,对于可查找的文件来说,不必是这样。

如果您tar使用 压缩存档gzip,将其作为一个整体进行压缩,则压缩算法会使用开头看到的数据进行压缩,因此您必须从头开始解压缩。

但是xz可以将格式配置为将数据压缩为单独的单独块(足够大以便压缩有效),这意味着只要您在这些压缩块的末尾保留索引,对于可查找文件,您就可以访问随机未压缩的数据(至少是块)。

pixz(parallel xz) 在压缩档案时使用该功能tar,还在文件末尾添加档案每个成员的开头索引xz

因此,对于可查找的文件,如果它们已被压缩,您不仅可以立即获得 tar 存档的内容列表(尽管没有元数据)pixz

pixz -l file.tar.xz

但您也可以提取单个元素,而无需阅读整个档案:

pixz -x archive/member.txt < file.tar.xz | tar xpf -

现在,至于为什么像7z或 之类的东西zip在 Unix 上很少使用,主要是因为它们无法归档 Unix 文件。它们是为其他操作系统设计的。您无法使用它们对数据进行忠实的备份。它们无法存储元数据,如所有者(id 和名称)、权限,它们无法存储符号链接、设备、fifo...,它们无法存储有关硬链接的信息,以及其他元数据信息,如扩展属性或 ACL。

其中一些甚至无法存储具有任意名称的成员(有些会因反斜杠、换行符、冒号或非 ascii 文件名而阻塞)(tar但某些格式也有限制)。

切勿将 tgz/tar.xz 文件解压缩到磁盘!

如果不明显,则不要使用tgztar.bz2, tar.xz... 存档作为:

unxz 文件.tar.xz
tar tvf 文件.tar
xz 文件.tar

如果您.tar的文件系统上有未压缩的文件,则说明您做错了什么。

这些xz流压缩器的全部意义在于它们可以在管道中动态使用,如bzip2gzip

unxz < file.tar.xz | tar tvf -

尽管现代tar实现知道如何自行调用unxz// gunzip,所以:bzip2

tar tvf file.tar.xz

通常也可以工作(并且再次动态解压缩数据,并且不在磁盘上存储存档的未压缩版本)。

例子

这是一个用各种格式压缩的 Linux 内核源代码树。

$ ls --block-size=1 -sS1
666210304 linux-4.6.tar
173592576 linux-4.6.zip
 97038336 linux-4.6.7z
 89468928 linux-4.6.tar.xz

首先,如上所述,7z 和 zip 略有不同,因为它们无法存储少数符号链接,并且丢失了大部分元数据。

现在刷新系统缓存后列出内容的一些时机:

$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3
$ time tar tvf linux-4.6.tar > /dev/null
tar tvf linux-4.6.tar > /dev/null  0.56s user 0.47s system 13% cpu 7.428 total
$ time tar tvf linux-4.6.tar.xz > /dev/null
tar tvf linux-4.6.tar.xz > /dev/null  8.10s user 0.52s system 118% cpu 7.297 total
$ time unzip -v linux-4.6.zip > /dev/null
unzip -v linux-4.6.zip > /dev/null  0.16s user 0.08s system 86% cpu 0.282 total
$ time 7z l linux-4.6.7z > /dev/null
7z l linux-4.6.7z > /dev/null  0.51s user 0.15s system 89% cpu 0.739 total

您会注意到,即使在这台已有 7 年历史的 PC 上,列出tar.xz文件也比列出文件要快,.tar因为从磁盘读取这些额外的兆​​字节比读取和解压缩较小的文件需要更长的时间。

然后好吧,用 7z 或 zip 列出档案会更快,但这不是问题,正如我所说,通过将文件列表与档案一起存储可以轻松解决这个问题:

$ tar tvf linux-4.6.tar.xz | xz > linux-4.6.tar.xz.list.xz
$ ls --block-size=1 -sS1 linux-4.6.tar.xz.list.xz
434176 linux-4.6.tar.xz.list.xz
$ time xzcat linux-4.6.tar.xz.list.xz > /dev/null
xzcat linux-4.6.tar.xz.list.xz > /dev/null  0.05s user 0.00s system 99% cpu 0.051 total

即使在删除缓存后,速度甚至比 7z 或 zip 还要快。您还会注意到,存档及其索引的累积大小仍然小于 zip 或 7z 存档。

或者使用pixz索引格式:

$ xzcat linux-4.6.tar.xz | pixz -9  > linux-4.6.tar.pixz
$ ls --block-size=1 -sS1 linux-4.6.tar.pixz
89841664 linux-4.6.tar.pixz
$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3
$ time pixz -l linux-4.6.tar.pixz > /dev/null
pixz -l linux-4.6.tar.pixz > /dev/null  0.04s user 0.01s system 57% cpu 0.087 total

现在,要提取存档的各个元素,tar 存档的最坏情况是访问最后一个元素时:

$ xzcat linux-4.6.tar.xz.list.xz|tail -1
-rw-rw-r-- root/root      5976 2016-05-15 23:43 linux-4.6/virt/lib/irqbypass.c
$ time tar xOf linux-4.6.tar.xz linux-4.6/virt/lib/irqbypass.c | wc
    257     638    5976
tar xOf linux-4.6.tar.xz linux-4.6/virt/lib/irqbypass.c  7.27s user 1.13s system 115% cpu 7.279 total
wc  0.00s user 0.00s system 0% cpu 7.279 total

这非常糟糕,因为它需要读取(并解压缩)整个存档。与之比较:

$ time unzip -p linux-4.6.zip linux-4.6/virt/lib/irqbypass.c | wc
    257     638    5976
unzip -p linux-4.6.zip linux-4.6/virt/lib/irqbypass.c  0.02s user 0.01s system 19% cpu 0.119 total
wc  0.00s user 0.00s system 1% cpu 0.119 total

我的 7z 版本似乎无法进行随机访问,所以它似乎比tar.xz

$ time 7z e -so linux-4.6.7z linux-4.6/virt/lib/irqbypass.c 2> /dev/null | wc
    257     638    5976
7z e -so linux-4.6.7z linux-4.6/virt/lib/irqbypass.c 2> /dev/null  7.28s user 0.12s system 89% cpu 8.300 total
wc  0.00s user 0.00s system 0% cpu 8.299 total

现在我们已经有了pixz之前生成的一个:

$ time pixz < linux-4.6.tar.pixz -x linux-4.6/virt/lib/irqbypass.c  | tar xOf - | wc
    257     638    5976
pixz -x linux-4.6/virt/lib/irqbypass.c < linux-4.6.tar.pixz  1.37s user 0.06s system 84% cpu 1.687 total
tar xOf -  0.00s user 0.01s system 0% cpu 1.693 total
wc  0.00s user 0.00s system 0% cpu 1.688 total

它速度更快,但仍然相对较慢,因为存档包含很少的大块:

$ pixz -tl linux-4.6.tar.pixz
 17648865 / 134217728
 15407945 / 134217728
 18275381 / 134217728
 19674475 / 134217728
 18493914 / 129333248
   336945 /   2958887

因此pixz仍然需要读取并解压缩(最多)~19MB 的大数据块。

我们可以通过使存档成为更小的块(并牺牲一点磁盘空间)来加快随机访问速度:

$ pixz -f0.25 -9 < linux-4.6.tar > linux-4.6.tar.pixz2
$ ls --block-size=1 -sS1 linux-4.6.tar.pixz2
93745152 linux-4.6.tar.pixz2
$ time pixz < linux-4.6.tar.pixz2 -x linux-4.6/virt/lib/irqbypass.c  | tar xOf - | wc
    257     638    5976
pixz -x linux-4.6/virt/lib/irqbypass.c < linux-4.6.tar.pixz2  0.17s user 0.02s system 98% cpu 0.189 total
tar xOf -  0.00s user 0.00s system 1% cpu 0.188 total
wc  0.00s user 0.00s system 0% cpu 0.187 total

答案2

  1. 尽管有这个缺点,为什么人们仍然如此使用它?

当事情发生故障时,企业和学术管理员往往会更容易受到关注,而不是在事情高效运行时受到赞赏。 这样的环境滋生对实验的恐惧,并且蔑视新奇

  1. 如果我想要“即时内容列表”功能,我有什么选择(我的意思是其他软件/工具)?

达尔D伊斯克氩气chiver)具有大量柏油类似的功能,加上增强功能,例如压缩档案的快速随机访问、AKA 编目、AKA 索引、AKA“即时内容列表”...

也可以看看:对档案中的随机访问提供良好支持的压缩格式?

相关内容