有几个库用于通过Python提取归档文件,例如gzip、zipfile库、rarfile、tarfile、patool等。我发现其中一个库(patool)特别有用,因为它具有跨格式的特性,因为它可以提取几乎任何类型的存档,包括最流行的归档,如ZIP、GZIP、TAR和RAR。
要使用patool提取存档文件,就像这样简单:
patoolib.extract_archive( "Archive.zip",outdir="Folder1")
其中,"Archive.zip"
是归档文件的路径,"Folder1"
是存储提取文件的目录的路径。
提取效果很好。问题是,如果我再次对完全相同的存档文件运行相同的代码,一个相同的提取文件将存储在同一个文件夹中,但名称略有不同(文件名在第一次运行时,filename1在第二次,filename11在第三次,等等)。
相反,如果目录中已经存在同名文件,则需要代码覆盖提取的文件。
这个extract_archive
函数看起来非常小-它只有这两个参数,一个verbosity
参数和一个program
参数,指定您想要提取存档的程序。
编辑: Nizam的答案记录了extract_archive
函数实际上正在覆盖输出。我发现这在一定程度上是正确的-函数覆盖ZIP文件,但不覆盖GZ文件,这正是我所追求的。对于GZ文件,该函数仍然生成新文件。
编辑了 Padraic Cunningham的答案,建议使用主源。所以,我下载了这段代码,用链接中的脚本替换了我以前的patool库脚本。结果如下:
os.listdir()
Out[11]: ['a.gz']
patoolib.extract_archive("a.gz",verbosity=1,outdir=".")
patool: Extracting a.gz ...
patool: ... a.gz extracted to `.'.
Out[12]: '.'
patoolib.extract_archive("a.gz",verbosity=1,outdir=".")
patool: Extracting a.gz ...
patool: ... a.gz extracted to `.'.
Out[13]: '.'
patoolib.extract_archive("a.gz",verbosity=1,outdir=".")
patool: Extracting a.gz ...
patool: ... a.gz extracted to `.'.
Out[14]: '.'
os.listdir()
Out[15]: ['a', 'a.gz', 'a1', 'a2']
因此,extract_archive
函数每次执行时都会创建新文件。在a.gz
下存档的文件实际上与a
有不同的名称。
发布于 2015-04-16 18:49:44
正如您已经说过的,patoolib旨在成为一个通用的归档工具。
使用patool可以创建、提取、测试、列出、比较、搜索和重新打包各种存档类型。patool的优点是它在处理归档文件时很简单,而不必记住无数的程序和选项。
通用提取行为与特定提取行为
这里的问题是,extract_archive
没有广泛地公开修改归档工具的底层默认行为的能力。
对于.zip扩展,patoolib将使用unzip。通过将-o作为选项传递给命令行接口,您可以具有提取存档的所需行为。例如,unzip -o ...
,这是解压缩的一个特定命令行选项,每个归档实用程序都会发生变化。
例如,tar提供了一个覆盖选项,但没有与zip等效的缩短命令行。也就是说,tar --overwrite
但是tar -o
没有预期的效果。
若要解决此问题,可以向作者发出功能请求,或使用其他库。不幸的是,patoolib的咒语需要扩展所有提取实用程序函数,然后实现底层提取器自己的覆盖命令选项。
示例更改为patoolib
在patoolib.programs.unzip
中
def extract_zip (archive, compression, cmd, verbosity, outdir, overwrite=False):
"""Extract a ZIP archive."""
cmdlist = [cmd]
if verbosity > 1:
cmdlist.append('-v')
if overwrite:
cmdlist.append('-o')
cmdlist.extend(['--', archive, '-d', outdir])
return cmdlist
在patoolib.programs.tar
中
def extract_tar (archive, compression, cmd, verbosity, outdir, overwrite=False):
"""Extract a TAR archive."""
cmdlist = [cmd, '--extract']
if overwrite:
cmdlist.append('--overwrite')
add_tar_opts(cmdlist, compression, verbosity)
cmdlist.extend(["--file", archive, '--directory', outdir])
return cmdlist
更新每个程序并不是微不足道的改变,每个程序都是不同的!
猴子修补覆盖行为
所以你决定不改进patoolib源代码..。我们可以覆盖extract_archive
的行为,以便最初查找现有目录,删除它,然后调用原始extract_archive
。
您可以将这段代码包含在您的模块中,如果许多模块需要它,也许可以将它粘贴到__init__.py
中。
import os
import patoolib
from shutil import rmtree
def overwrite_then_extract_archive(archive, verbosity=0, outdir=None, program=None):
if outdir:
if os.path.exists(outdir):
shutil.rmtree(outdir)
patoolib.extract_archive(archive, verbosity, outdir, program)
patoolib.extract_archive = overwrite_then_extract_archive
现在,当我们调用extract_archive()
时,我们有了overwrite_then_extract_archive()
的功能。
发布于 2015-04-16 18:44:00
如果功能不存在,则需要添加它。这方面的一个例子是用您自己的一个函数包装:
import os
from shutil import rmtree
def overwriting_extract_archive(zippath, outpath, **kwargs):
if os.path.exists(outpath):
shutil.rmtree(outpath)
patoolib.extract_archive(zippath, outdir=outpath, **kwargs)
当然,如果您想逐文件检查新输出并将新输出与现有输出合并,这将成为一个更复杂的问题,但是如果它正如您所描述的(第二次运行它),这应该是可行的。
发布于 2015-04-21 20:56:40
如果提取失败,则在解压缩存档时覆盖现有文件可能会使目标目录处于不一致状态。
在解压缩之前删除目标目录可能会导致文件丢失,如果解压缩失败。
我认为最好的方法是提取到临时目录并同步到目标目录。
对于此解决方案,需要模块dirsync
。但是,只有在默认情况下,dirsync
和ctime
是更新的,而不是文件大小。
import os
import sys
from shutil import rmtree
from patoolib import extract_archive
from dirsync import sync
archive = ''
dst_dir = ''
try:
tmp_dir = extract_archive(archive)
except Exception as e:
print('extract_archive error {}'.format(e))
sys.exit(1)
else:
try:
sync(tmp_dir,dst_dir,'sync',options=['modtime'])
except Exception as e:
print('updating {} from {} failed, error {}'.format(dst_dir,tmp_dir,e))
sys.exit(1)
else:
sys.exit(0)
finally:
if os.path.exists(tmp_dir):
rmtree(tmp_dir)
https://stackoverflow.com/questions/29631793
复制相似问题