覆盖以前提取的文件而不是创建新文件

mul*_*rse 11 python file extract overwrite ziparchive

有一些库用于通过Python提取存档文件,例如gzip,zipfile库,rarfile,tarfile,patool等.我发现其中一个库(patool)特别有用,因为它具有交叉格式功能它可以提取几乎任何类型的存档,包括最流行的存档,如ZIP,GZIP,TAR和RAR.

要使用patool提取存档文件,它就像这样简单:

patoolib.extract_archive( "Archive.zip",outdir="Folder1")
Run Code Online (Sandbox Code Playgroud)

其中"Archive.zip"是存档文件"Folder1"的路径,而是存储解压缩文件的目录的路径.

提取工作正常.问题是,如果我为完全相同的存档文件再次运行相同的代码,则相同的提取文件将存储在同一文件夹中,但名称略有不同(第一次运行时为文件名,第二次运行时为filename1,文件名为11)第三,等等.

如果目录中已经存在同名文件,我需要代码来覆盖提取的文件.

这个extract_archive函数看起来很小 - 它只有这两个参数,一个verbosity参数和一个program参数,它指定了你想要提取档案的程序.

编辑: Nizam Mohamed的回答记录了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']
Run Code Online (Sandbox Code Playgroud)

因此,该extract_archive功能再次在每次执行时创建新文件.存档的文件a.gz具有与a实际不同的名称.

Mat*_*son 5

正如您所说,patoolib 旨在成为一个通用的归档工具。

使用 patool 可以创建、提取、测试、列出、比较、搜索和重新打包各种存档类型。patool 的优点是处理存档文件的简单性,无需记住大量的程序和选项。

通用提取行为与特定提取行为

这里的问题是extract_archive没有公开广泛修改存档工具的底层默认行为的能力。

对于 .zip 扩展名,patoolib 将使用 unzip。您可以通过将 -o 作为选项传递给命令行界面来获得提取存档的所需行为。ieunzip -o ...但是,这是解压缩的特定命令行选项,并且每个存档实用程序都会发生变化。

例如,tar 提供了覆盖选项,但没有与 zip 等效的缩短命令行。即tar --overwritetar -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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

更新每个程序并不是一个简单的更改,每个程序都是不同的!

猴子修补覆盖行为

所以您决定不改进 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
Run Code Online (Sandbox Code Playgroud)

现在,当我们调用时,extract_archive()我们具有overwrite_then_extract_archive().


a p*_*a p 2

如果该功能不存在,您需要添加它。一个例子是用您自己的函数包装该函数:

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)
Run Code Online (Sandbox Code Playgroud)

如果您想逐个文件检查并将新输出与现有输出合并,这当然会成为一个更复杂的问题,但如果正如您所描述的那样(第二次运行它),这应该可行。