情境
我正在壓縮大約 1.3 GB 的資料夾,每個資料夾包含 1440 個 JSON 文件,發現使用該tar
命令與 Python 的內建命令之間存在 15 倍的差異tarfile
macOS 上的庫或樹莓派 10(巴斯特)
最小工作範例
該腳本比較了兩種方法:
#!/usr/bin/env python3
from pathlib import Path
from subprocess import call
import tarfile
fullpath = Path("/Users/user/Desktop/temp/tar/2021-03-11")
zsh_out = Path(fullpath.parent, "zsh-archive.tar.xz")
py_out = Path(fullpath.parent, "py-archive.tar.xz")
# tar using terminal
# tar cJf zsh-archive.tar.xz folderpath
call(["tar", "cJf", zsh_out, fullpath])
# tar using tarfile library
with tarfile.open(py_out, "w:xz") as tar:
tar.add(fullpath, arcname=fullpath.stem)
# Print filesizes
print(f"zsh tar filesize: {round(Path(zsh_out).stat().st_size/(1024*1024), 2)} MB")
print(f"py tar filesize: {round(Path(py_out).stat().st_size/(1024*1024), 2)} MB")
輸出是:
zsh tar filesize: 23.7 MB
py tar filesize: 1.49 MB
我使用的版本如下:
tar
在 macOS 上:bsdtar 3.3.2 - libarchive 3.3.2 zlib/1.2.11 liblzma/5.0.5 bz2lib/1.0.6
tar
在 Raspbian 10 上:xz (XZ Utils) 5.2.4 liblzma 5.2.4
tarfile
Python 函式庫:0.9.0
我嘗試過的事情
壓縮後,我提取了兩個檔案並將生成的資料夾與以下內容進行比較:
diff -r py-archive-expanded zsh-archive-expanded
沒有什麼差別。
如果我直接比較兩個 tar 檔案,它們看起來不同:
➜ diff zsh-archive.tar.xz py-archive.tar.xz
Binary files zsh-archive.tar.xz and py-archive.tar.xz differ
如果我使用 Quicklook(和 Betterzip 外掛程式)檢查檔案,我會發現檔案中的文件以不同的方式排序:
左邊是zsh-archive.tar.xz
,右邊是py-archive.tar.xz
:
zsh 檔案使用未知順序,而 Python 檔案則會依修改日期對檔案進行排序。我不確定這是否重要。
問題
到底是怎麼回事?使用 Python 庫壓縮資料會丟失一些東西嗎? 15 倍的大小差異是否表示存在某些問題?或者我可以安全地繼續使用高效能的 Python 實作嗎?
答案1
簡短的回答:是的,使用 Pythontarlib
壓縮資料是安全的,與 BSD 相比沒有任何損失tar
。
根本問題:排序
我認為根本問題是 BSDtar
和 GNUtar
沒有任何排序選項,以未定義的順序將檔案放入存檔中。
GNUtar
有一個--sort
選項:
根據 排序目錄條目,它是、或
ORDER
之一。 預設值為,它會按照作業系統傳回的順序儲存存檔成員。none
name
inode
--sort=none
測試 GNUtar
為了測試這一點,我tar
在我的 Mac 上安裝了 GNU:
brew install gnu-tar
然後對同一個資料夾進行 tar 壓縮,但使用以下--sort
選項:
gtar --sort='name' -cJf zsh-archive-sorted.tar.xz /Users/user/Desktop/temp/tar/2021-03-11
此zsh-archive-sorted.tar.xz
存檔大小為 1.5 MB,等於 Python 庫所建立的存檔的大小。
按排序順序連接
透過先連接所有按名稱排序的 JSON 檔案(其開頭有建立 unixtime),然後使用 BSD 壓縮,進一步證明了排序對最終存檔大小的影響tar
:
cat *.json > all.txt
tar cJf zsh-cat-archive.tar.xz all.txt
檔案zsh-cat-archive.tar.xz
也有 1.5 MB。
Pythontarfile
排序
最後,PythonTarFile.add
函數的文檔確認 Pythontarfile
預設排序:
預設情況下,目錄是遞歸添加的。將 recursive 設為 False 可以避免這種情況。遞歸按排序順序新增條目。
為什麼排序很重要
我認為排序對我的案例有如此影響的原因如下:
我的 JSON 檔案包含數百輛車輛的位置。我每分鐘都會讀出所有位置,但其中只有少數位置每分鐘都有不同的數值。
透過按名稱對文件進行排序,兩個後續文件之間的字元幾乎沒有不同。顯然這對於壓縮效率非常有利。
答案2
嘗試在 macOS 命令列中設定壓縮等級。
我知道你在問xz
但解釋在這個答案在這裡,在舊版的 GZip 上,您可以使用環境變數設定壓縮級別,如下所示:
GZIP=-9 tar cf zsh-archive.tar.xz folderpath
也就是說,這似乎只適用於 GZip 1.8,並且在更高版本中已被棄用。因此,請使用tar 的-I
/選項;--use-compress-program=COMMAND
請注意,此選項可能不適用於 macOS,但為了以防萬一,還是放在這裡。因此命令將更改為:
tar -I 'gzip -9' -cf zsh-archive.tar.xz folderpath
是的,這些範例將壓縮存檔 Gzip 而不是xz
,但您可以輕鬆地將命令變更為xz
這樣使用:
tar -I 'xz -9' -cf zsh-archive.tar.xz folderpath
壓縮xz
等級範圍從-0
到-9
,預設為-6
;-9
最高壓縮等級也是如此。
請注意,xz
預設情況下,macOS 上並未安裝。要在 macOS 上安裝它,您必須先安裝自製然後安裝xz
透過 Homebrew 像這樣:
brew install xz
答案3
讓我想知道 Python 使用什麼來進行壓縮
它可能使用 liblzma 中的函數呼叫。柏油可能是透過 xz shell 指令進行管道傳輸。
快速評論--sort=name
:
排序選項是 GNU tar 的一個相對較新的增強功能,在 tar 版本 1.28 中引入。
它可能永遠不會在 BSD tar 中實現。