使用Python的tarfile时如何覆盖现有只读文件
我正在尝试使用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之前,递归地修改目标文件的权限其实并不难。或者我可以使用shutil.rmtree先把目标文件删除,这也是我现在在用的解决办法。不过,这样做感觉有点不太优雅。
有没有更符合Python风格的方法来处理tarfile中覆盖只读文件的问题,比如使用异常处理或者其他类似的方式?
2 个回答
3
我成功让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)
11
你可以遍历压缩包里的每个文件,并在处理每个文件时检查错误:
在现代版本的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:
如果你的压缩包是gz格式的,有个简单的方法可以处理,只需要:
tarfile.open('myfile.tar.gz', 'r:gz')
如果 tarfile.extractall
有一个覆盖选项,那就更好了。