从 tar 中仅提取单个目录(在 python 中)

问题描述 投票:0回答:3

我正在使用 python 开发一个项目,其中我只需要提取 tar 存档的一个子文件夹,而不是所有文件。 我尝试使用

tar = tarfile.open(tarfile)
tar.extract("dirname", targetdir)

但这不起作用,它不会提取给定的子目录,也不会抛出异常。我是Python的初学者。 另外,如果上述函数不适用于目录,那么此命令和 tar.extractfile() 有什么区别?

python tar
3个回答
22
投票

基于 tarfile 模块文档中的第二个示例,您可以使用如下方式提取包含的子文件夹及其所有内容:

with tarfile.open("sample.tar") as tar:
    subdir_and_files = [
        tarinfo for tarinfo in tar.getmembers()
        if tarinfo.name.startswith("subfolder/")
    ]
    tar.extractall(members=subdir_and_files)

这将创建子文件夹及其内容的列表,然后使用推荐的

extractall()
方法仅提取它们。当然,请将
"subfolder/"
替换为您要提取的子文件夹的实际路径(相对于 tar 文件的根目录)。


16
投票

另一个答案将保留子文件夹路径,这意味着

subfolder/a/b
将被提取到
./subfolder/a/b
。要将子文件夹提取到根目录,以便将
subfolder/a/b
提取到
./a/b
,您可以使用如下方式重写路径:

def members(tf):
    l = len("subfolder/")
    for member in tf.getmembers():
        if member.path.startswith("subfolder/"):
            member.path = member.path[l:]
            yield member

with tarfile.open("sample.tar") as tar:
    tar.extractall(members=members(tar))

0
投票

所有其他解决方案的问题是它们需要在提取之前访问文件的末尾 - 这意味着它们不能应用于不支持查找的流。

使用 Python 3.12(我还没有找到早期版本的方法):

strip1 = lambda member, path: member.replace(name=pathlib.Path(*pathlib.Path(member.path).parts[1:]))
with tarfile.open('file.tar.gz', mode='r:gz') as input:
    input.extractall(path=dest, filter=strip1)

extractall
接受一个过滤器,该过滤器会通过
TarInfo
为每个文件调用 - 您解压文件名,取出除第一个部分之外的所有部分,然后重新打包。

© www.soinside.com 2019 - 2024. All rights reserved.