【问题标题】:How can I extract files to a different destination filename from tarfile in python?如何从 python 中的 tarfile 将文件提取到不同的目标文件名?
【发布时间】:2021-03-17 08:41:04
【问题描述】:

我有一个tarfile.TarFile,我想从中提取一些文件到修改后的目标文件名;有一个与存档成员同名的现有文件,我不想触碰。 具体来说,我想附加一个后缀,例如存档中名为 foo/bar.txt 的成员应提取为 foo/bar.txt.mysuffix

这两种有些明显但又有些不令人满意的方法是:

  • 使用extractfile提取每个文件,创建重命名文件并使用shutil.copyfileobj复制内容;但是,这仅限于常规文件或所有特殊处理,例如在 tarfile 中实现的稀疏文件、符号链接、目录等必须被复制。
  • extractall 到一个临时目录,然后重命名并复制到目标;这只是让人感到不必要的复杂,需要与主机系统进行更多交互并引入新的故障模式,而且似乎很容易犯这种微妙的错误(例如,请参阅shutil.copy/copy2 上的警告)。

TarFile 上是否没有接口或钩子可以简洁而正确地实现这一点?

【问题讨论】:

  • 您提到创建重命名文件并从提取的文件中复制内容,但我不明白仅在原地重命名提取的文件有什么问题?
  • 对,对不起,这是一些缺失的上下文;原因是目标名称下有一个现有文件,我不想覆盖它。我会把这个添加到问题中。

标签: python tarfile


【解决方案1】:

TarFile.getmembers() 方法可以将存档的成员作为列表返回。 在那里你可以循环并选择你想提取或不提取的文件。根据你的 tar 的大小,你的第二种方法也是可行的,但不是最好的。

object = tarfile.open('example.tar', 'r')
for member in object.getmembers():
    if "whatever" in member.name:
        object.extract(member, "example_dir")

【讨论】:

  • 好的,当然,但这不允许在提取单个文件时重命名它们。
  • 这是一个非常简单的操作系统调用,你能详细说明为什么需要重命名吗?
  • 是的,很抱歉问题中缺少了这一点;有一个与存档成员同名的现有文件,我不想碰它。
【解决方案2】:

翻阅Lib/tarfile.py,偶然发现了这个comment

    #--------------------------------------------------------------------------
    # Below are the different file methods. They are called via
    # _extract_member() when extract() is called. They can be replaced in a
    # subclass to implement other functionality.

    def makedir(self, tarinfo, targetpath):
       #...
    
    def makefile(self, tarinfo, targetpath):
       # ...

官方参考文档中没有提到这些方法,但它们似乎是公平的游戏。要在现有打开的TarFile 实例上覆盖这些,我们可以创建一个子类 Facade/Wrapper:

class SuffixingTarFile(tarfile.TarFile):
    def __init__(self, suffix: str, wrapped: tarfile.TarFile):
        self.suffix = suffix
        self.wrapped = wrapped

    def __getattr__(self, attr):
        return getattr(self.wrapped, attr)

    def makefile(self, tarinfo, targetpath):
        super().makefile(tarinfo, targetpath + self.suffix)

    # overwrite makedir, makelink, makefifo, etc. as desired

例子:

tar = tarfile.open(...)
star = SuffixingTarFile(".foo", tar)
star.extractall()  # extracts all (regular) file members with .foo suffix appended

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-24
    • 1970-01-01
    • 2020-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多