我该如何使用Python创建一个带有压缩的.tar.gz文件?
我该如何使用Python创建一个带有压缩的.tar.gz文件?
为整个目录树构建一个.tar.gz
(也称为.tgz
)的方法:
import tarfile
import os.path
def make_tarfile(output_filename, source_dir):
with tarfile.open(output_filename, "w:gz") as tar:
tar.add(source_dir, arcname=os.path.basename(source_dir))
这将创建一个压缩的tar档案,其中包含一个顶层文件夹,其名称和内容与source_dir
相同。
arcname=os.path.basename(source_dir)
这部分代码,将会在 tar 文件中保留整个 source_dir
的路径结构(在大多数情况下,这会造成不便)。 - Brōtsyorfuzthrāxarcname=os.path.basename(source_dir)
仍然意味着归档文件包含一个文件夹,其中包含 source_dir
的内容。如果你想要归档文件的根目录包含这些内容本身,而不是一个文件夹内的内容,请使用 arcname=os.path.sep
。 - Jonathan Hos.path.sep
,归档文件将包含服务“。”或“/”文件夹,通常不是问题,但有时在以后编程处理此归档文件时可能会出现问题。似乎唯一真正干净的方式是使用os.walk
并逐个添加文件。 - The Godfatherarcname='.'
。不需要使用os.walk
。 - edthrn格式
;在Python 3.8之前的默认格式是“GNU_FORMAT”,可能不被所有工具读取,但截至Python 3.8的默认格式是“PAX_FORMAT”,这是一种标准格式,也是旧有标准USTAR_FORMAT
的保守/兼容扩展,被广泛支持。 - kbolinoimport tarfile
tar = tarfile.open("sample.tar.gz", "w:gz")
for name in ["file1", "file2", "file3"]:
tar.add(name)
tar.close()
如果你想创建一个tar.bz2压缩文件,只需要将文件扩展名替换为".tar.bz2",并将"w:gz"替换为"w:bz2"。with tarfile.open(…)
,而不是手动调用open
和close
。这也适用于打开普通文件。 - Jonathan H你可以使用 tarfile.open 方法并设置 mode='w:gz'
来进行 gzip 压缩写入操作。
通常建议将文件名(传递给 open
方法的 name
参数)以 .tar.gz
结尾,但这不会影响压缩效果。
顺便说一下,设置为 'w:bz2'
模式时通常可以获得更好的压缩效果。就像通过 bzip2
而不是 gzip
进行压缩时,tar
通常也能够获得更好的压缩率。
之前的答案建议使用Python中的tarfile
模块创建.tar.gz
文件。显然,这是一种好的Python风格的解决方案,但它在打包速度上有明显的缺陷。 这个问题 提到,tarfile
比Linux中的tar
工具慢大约两倍。根据我的经验,这个估计相当正确。
因此,为了更快地打包,您可以使用subprocess
模块中的tar
命令:
subprocess.call(['tar', '-czf', output_filename, file_to_archive])
shutil.make_archive 对于文件和目录(递归添加到档案中)非常方便:
import shutil
compressed_file = shutil.make_archive(
base_name='archive', # archive file name w/o extension
format='gztar', # available formats: zip, gztar, bztar, xztar, tar
root_dir='path/to/dir' # directory to compress
)
除了 @Aleksandr Tukallo的回答之外,您还可以获取输出和错误消息(如果有发生)。使用 tar
压缩文件夹的方法在以下回答中解释得相当清楚。
import traceback
import subprocess
try:
cmd = ['tar', 'czfj', output_filename, file_to_archive]
output = subprocess.check_output(cmd).decode("utf-8").strip()
print(output)
except Exception:
print(f"E: {traceback.format_exc()}")
在这个tar.gz文件中,压缩了一个公开可见的目录。在解决方案中使用os.path.basename(file_directory)。
import tarfile
with tarfile.open("save.tar.gz","w:gz") as tar:
for file in ["a.txt","b.log","c.png"]:
tar.add(os.path.basename(file))
在目录中压缩tar.gz文件的使用
对 @THAVASI.T 的答案进行了小修正,补充了 'tarfile' 库的导入,并定义了第三行中使用的 'tar' 对象。
import tarfile
with tarfile.open("save.tar.gz","w:gz") as tar:
for file in ["a.txt","b.log","c.png"]:
tar.add(os.path.basename(file))
只是在更清晰的形式下重新阐述@George V. Reilly的出色回答...
import tarfile
fd_path="/some/folder/path/"
fl_name="some_file_name.ext"
targz_fd_path_n_fl_name="/some/folder/path/some_file_name.tar.gz"
with tarfile.open(targz_fd_path_n_fl_name, "w:gz") as tar:
tar.add(fd_path + fl_name, fl_name)
fd_path + fl_name
的完整路径结构。import tarfile
import os
fd_path_n_fl_name="/some/folder/path/some_file_name.ext"
targz_fd_path_n_fl_name="/some/folder/path/some_file_name.tar.gz"
with tarfile.open(targz_fd_path_n_fl_name, "w:gz") as tar:
tar.add(fd_path_n_fl_name, os.path.basename(fd_path_n_fl_name))
如果您不想使用或没有文件夹路径和文件名分开,可以这样做。
谢谢!
在压缩文件中实现最佳性能,且不包含 .
和 ..
!请见下方漏洞警告:
注意(感谢MaxTruxa):
此答案易受shell注入攻击。请阅读文档中的安全注意事项。如果使用
shell=True
,永远不要传递未经转义的字符串给subprocess.run
,subprocess.call
等函数。仅对Unix shell使用shlex.quote
进行转义。我正在本地使用它,所以对我的需求很好。
subprocess.call(f'tar -cvzf {output_filename} *', cwd=source_dir, shell=True)
cwd
参数在压缩之前更改目录 - 这解决了点的问题。
shell=True
允许使用通配符(*
)
也适用于递归目录
shell=True
,不要将未转义的字符串传递给subprocess.run
,subprocess.call
等函数。请使用shlex.quote
进行转义(仅适用于Unix Shell)。 - Max Truxa