语境
我正在压缩 ~1.3 GB 文件夹,每个文件夹都包含 1440 个 JSON 文件,发现在 macOS 或Raspbian 10 (Buster)上使用tar
命令和 Python 的内置库之间存在 15 倍的差异tarfile
最小的工作示例
此脚本比较两种方法:
#!/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 实现吗?
简短回答:是的,使用 Python
tarlib
压缩数据是安全的,与 BSD 相比没有任何损失tar
。基本问题:排序
我认为根本问题是没有任何排序选项的 BSD
tar
和 GNUtar
以未定义的顺序将文件放入存档中。GNU
tar
有一个--sort
选项:测试 GNU
tar
tar
为了测试这一点,我在我的 Mac 上安装了 GNU :然后对同一个文件夹进行 tar 处理,但可以
--sort
选择:zsh-archive-sorted.tar.xz
存档为 1.5 MB,等于 Python 库创建的存档大小。按排序顺序连接
排序对最终存档大小的影响通过首先连接所有按名称排序的 JSON 文件(在其开头具有创建 unixtime)然后使用 BSD 进行 tarring 来进一步证明
tar
:zsh-cat-archive.tar.xz
存档也是 1.5 MB 。Python
tarfile
排序最后, Python函数的文档
TarFile.add
确认 Pythontarfile
默认排序:为什么排序很重要
我认为排序对我的情况有如此影响的原因如下:
我的 JSON 文件包含数百辆汽车的位置。我每分钟都会读出所有位置,但只有少数几个位置每分钟都有不同的值。
通过按名称对文件进行排序,两个后续文件之间几乎没有不同的字符。显然这对压缩效率非常有利。
尝试在 macOS 命令行中设置压缩级别。
我知道您在询问
xz
但在此答案中进行了解释,在旧版本的 GZip 上,您可以使用如下环境变量设置压缩级别:也就是说,这似乎只适用于 GZip 1.8,并且在以后的版本中被贬值。所以使用
-I
/--use-compress-program=COMMAND
选项 tar 代替;请注意,此选项在 macOS 上可能不起作用,但无论如何都放在这里以防万一。因此命令将更改为:是的,这些示例将压缩存档 Gzip 而不是 .
xz
,但您可以轻松地将命令更改为此使用,xz
如下所示:xz
压缩级别范围从-0
到,-9
默认为-6
;-9
最高压缩级别也是如此。请注意,
xz
默认情况下未安装在 macOS 上。要在 macOS 上安装它,您必须先安装Homebrew,然后xz
通过 Homebrew 安装,如下所示:http://tukaani.org/xz/
它可能使用 liblzma 中的函数调用。Tar可能正在通过 xz shell 命令进行管道传输。
快速评论
--sort=name
:排序选项是对 GNU tar 的相对较新的增强,并在 tar 版本 1.28 中引入。
它可能永远不会在 BSD tar 中实现。