如何将文件从 python 中的 tarfile 提取到不同的目标文件名?
How can I extract files to a different destination filename from tarfile in python?
我有一个 tarfile.TarFile
,我想从中提取一些文件到修改后的目标文件名;有一个与存档成员同名的现有文件,我不想触及。
具体来说,我想附加一个后缀,例如存档中名为 foo/bar.txt
的成员应提取为 foo/bar.txt.mysuffix
.
两个有些明显但也有些不尽如人意的方法是:
- 使用
extractfile
提取每个文件,使用 shutil.copyfileobj
创建重命名的文件并复制内容;然而,这要么仅限于常规文件,要么必须复制 tarfile
中实现的所有特殊处理,例如稀疏文件、符号链接、目录等。
extractall
到一个临时目录,然后重命名并复制到目标;这只是感觉不必要的复杂,需要与主机系统进行更多交互并引入新的故障模式,而且似乎很容易弄错这个微妙的错误(例如,请参阅 shutil.copy/copy2
上的警告)。
TarFile
上是否没有接口或挂钩可以简洁正确地实现这一点?
有TarFile.getmembers() 方法returns 将存档的成员作为列表。
在那里你可以循环并选择你想要提取的文件或 not.Depending 你的 tar 的大小,你的第二种方法也可行但不是最好的。
object = tarfile.open('example.tar', 'r')
for member in object.getmembers():
if "whatever" in member.name:
object.extract(member, "example_dir")
浏览Lib/tarfile.py
, I came across this 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
我有一个 tarfile.TarFile
,我想从中提取一些文件到修改后的目标文件名;有一个与存档成员同名的现有文件,我不想触及。
具体来说,我想附加一个后缀,例如存档中名为 foo/bar.txt
的成员应提取为 foo/bar.txt.mysuffix
.
两个有些明显但也有些不尽如人意的方法是:
- 使用
extractfile
提取每个文件,使用shutil.copyfileobj
创建重命名的文件并复制内容;然而,这要么仅限于常规文件,要么必须复制tarfile
中实现的所有特殊处理,例如稀疏文件、符号链接、目录等。 extractall
到一个临时目录,然后重命名并复制到目标;这只是感觉不必要的复杂,需要与主机系统进行更多交互并引入新的故障模式,而且似乎很容易弄错这个微妙的错误(例如,请参阅shutil.copy/copy2
上的警告)。
TarFile
上是否没有接口或挂钩可以简洁正确地实现这一点?
有TarFile.getmembers() 方法returns 将存档的成员作为列表。 在那里你可以循环并选择你想要提取的文件或 not.Depending 你的 tar 的大小,你的第二种方法也可行但不是最好的。
object = tarfile.open('example.tar', 'r')
for member in object.getmembers():
if "whatever" in member.name:
object.extract(member, "example_dir")
浏览Lib/tarfile.py
, I came across this 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