【问题标题】:How do I extract only the file of a .tar.gz member?如何仅提取 .tar.gz 成员的文件?
【发布时间】:2016-10-11 16:00:48
【问题描述】:

我的目标是解压.tar.gz 文件,而不是解压该文件的子目录。

我的代码基于此question,除了解压缩.zip 之外,我正在解压缩.tar.gz 文件。

我问这个问题是因为我得到的错误非常模糊,并且没有在我的代码中发现问题:

import os
import shutil
import tarfile

with tarfile.open('RTLog_20150425T152948.gz', 'r:gz') as tar:
    for member in tar.getmembers():
        filename = os.path.basename(member.name)
        if not filename:
            continue

        # copy file (taken from zipfile's extract)
        source = member
        target = open(os.path.join(os.getcwd(), filename), "wb")
        with source, target:
            shutil.copyfileobj(source, target)

如您所见,我从链接问题中复制了代码,并尝试将其更改为处理 .tar.gz 成员而不是 .zip 成员。运行代码时出现以下错误:

Traceback (most recent call last):
  File "C:\Users\dzhao\Desktop\123456\444444\blah.py", line 27, in <module>
    with source, target:
AttributeError: __exit__

根据我所做的阅读,shutil.copyfileobj 将两个“类文件”对象作为输入。 member 是一个 TarInfo 对象。我不确定TarInfo 对象是否是类似文件的对象,所以我尝试将这一行从:

source = member #to
source = open(os.path.join(os.getcwd(), member.name), 'rb')

但这可以理解地引发了找不到文件的错误。

我不明白什么?

【问题讨论】:

    标签: python python-3.x tar


    【解决方案1】:

    这段代码对我有用:

    import os
    import shutil
    import tarfile
    
    with tarfile.open(fname, "r|*") as tar:
        counter = 0
    
        for member in tar:
            if member.isfile():
                filename = os.path.basename(member.name)
                if filename != "myfile": # do your check
                    continue
    
                with open("output.file", "wb") as output: 
                    shutil.copyfileobj(tar.fileobj, output, member.size)
    
                break # got our file
    
            counter += 1
            if counter % 1000 == 0:
                tar.members = [] # free ram... yes we have to do this manually
    

    但您的问题可能不是提取,而是您的文件确实不是 .tar.gz 而只是一个 .gz 文件。

    编辑:由于python试图调用成员对象的__enter__函数(至尊不存在),因此您在 with 行也收到错误。

    【讨论】:

    • 我知道我的文件肯定是 .tar.gz。当我删除我的with source, target 行时,我最初的恐惧是正确的。看来我的来源不是类似文件的对象。我会在阅读 tar.fileobj 的作用后尝试您的代码。
    • 解决方法是将源更改为tar.fileobj。有趣的是,当我在 tar 文档页面上执行 ctrl+f 时,它不是一个函数。所以它必须是一些变量。但重要的是 tar.fileobj 是一个类似文件的对象,所以现在我的代码可以工作了 =) 谢谢!
    • 不客气。如果您正在处理大文件(100 MB),我强烈建议您包括免费 ram 行。文档中没有提到这一点,但如果您的脚本突然失败并且内存使用率过高,您会感到惊讶。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    相关资源
    最近更新 更多