Tar

立即列印存檔文件列表(無需解壓縮整個存檔)

  • September 6, 2020

存檔的一個問題.tar.gz是,當我嘗試僅列出存檔的內容時,電腦實際上會對其進行解壓縮,如果文件很大,這將需要很長時間。

其他文件格式,如.7z, .rar.zip沒有這個問題。列出他們的內容只需要一瞬間。

在我看來,這是.tar.gz存檔格式的一個巨大缺點。

所以我實際上有兩個問題:

  1. 儘管有這個缺點,為什麼人們使用.tar.gz這麼多?
  2. 如果我想要“即時內容列表”功能,我有哪些選擇(我的意思是其他軟體或工具)?

重要的是要了解這裡有一個權衡。

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 -

現在,至於為什麼喜歡7zzip很少在 Unix 上使用這些東西,主要是因為它們無法歸檔 Unix 文件。它們是為其他作業系統設計的。您無法使用它們對數據進行忠實備份。它們不能儲存諸如所有者(id 和名稱)、權限之類的元數據,它們不能儲存符號連結、設備、fifos……,它們不能儲存有關硬連結的資訊,以及諸如擴展屬性或 ACL 之類的其他元數據資訊。

其中一些甚至不能儲存具有任意名稱的成員(有些會因反斜杠或換行符或冒號或非 ascii 文件名而窒息)(tar儘管某些格式也有限制)。

永遠不要將 tgz/tar.xz 文件解壓到磁碟!

如果不明顯,請不要使用tgzor tar.bz2, tar.xz… 存檔:

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

如果你.tar的文件系統上有一個未壓縮的文件,那就是你做錯了什麼。

這些//作為流壓縮器的全部意義xz在於bzip2它們gzip可以在執行中使用,在管道中,如

unxz < file.tar.xz | tar tvf -

儘管現代tar實現知道如何自己呼叫unxz// gunzipbzip2所以:

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

引用自:https://unix.stackexchange.com/questions/287087