12

我正在尝试使用 Python 的 tarfile 模块来提取 tar.gz 存档。

我希望提取覆盖它们已经存在的任何目标文件 - 这是 tarfile 的正常行为。

但是,我打了一个告密者,因为某些文件具有写保护(例如 chmod 550)。

tarfile.extractall()操作实际上失败了:

IOError: [Errno 13] Permission denied '/foo/bar/file'

如果我尝试从普通命令行中删除文件,我可以做到,我只需要回答一个提示:

$ rm <filename>
rm: <filename>: override protection 550 (yes/no)? yes

普通的 GNU tar 实用程序也可以毫不费力地处理这些文件——它只是在您提取时覆盖它们。

我的用户是文件的所有者,因此在运行 tarfile.extractall 之前递归地对目标文件进行 chmod 并不难。或者我可以使用 shutil.rmtree 事先吹走目标,这是我现在正在使用的解决方法。但是,这感觉有点骇人听闻。

是否有更 Pythonic 的方式来处理覆盖 tarfile 中的只读文件、使用异常或类似的方法?

4

2 回答 2

10

您可以遍历 tarball 的成员并提取/处理每个文件上的错误:

在现代版本的 Python 中,我会使用以下with语句:

import os, tarfile

with tarfile.TarFile('myfile.tar', 'r', errorlevel=1) as tar:
    for file_ in tar:
        try:
            tar.extract(file_)
        except IOError as e:
            os.remove(file_.name)
            tar.extract(file_)
        finally:
            os.chmod(file_.name, file_.mode)

如果您不能使用with,只需将with语句块替换为:

tarball = tarfile.open('myfile.tar', 'r', errorlevel=1)
for file_ in tar:

如果您的 tar 球是 gzip 压缩的,则有一个快速的快捷方式来处理它,只需:

tarfile.open('myfile.tar.gz', 'r:gz')

如果tarfile.extractall有覆盖选项会更好。

于 2011-08-30T00:49:32.890 回答
2

我能够让 Mike 的 Steder 的代码像这样工作:

tarball = tarfile.open(filename, 'r:gz')
for f in tarball:
    try: 
        tarball.extract(f)
    except IOError as e:
        os.remove(f.name)
        tarball.extract(f)
    finally:
        os.chmod(f.name, f.mode)
于 2012-06-19T17:49:43.720 回答