首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >覆盖先前提取的文件,而不是创建新文件

覆盖先前提取的文件,而不是创建新文件
EN

Stack Overflow用户
提问于 2015-04-14 15:45:59
回答 5查看 10.9K关注 0票数 12

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

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

代码语言:javascript
运行
复制
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库脚本。结果如下:

代码语言:javascript
运行
复制
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有不同的名称。

EN

回答 5

Stack Overflow用户

发布于 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

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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中。

代码语言:javascript
运行
复制
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()的功能。

票数 5
EN

Stack Overflow用户

发布于 2015-04-16 18:44:00

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

代码语言:javascript
运行
复制
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)

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

票数 2
EN

Stack Overflow用户

发布于 2015-04-21 20:56:40

如果提取失败,则在解压缩存档时覆盖现有文件可能会使目标目录处于不一致状态。

在解压缩之前删除目标目录可能会导致文件丢失,如果解压缩失败。

我认为最好的方法是提取到临时目录并同步到目标目录。

对于此解决方案,需要模块dirsync。但是,只有在默认情况下,dirsyncctime是更新的,而不是文件大小。

代码语言:javascript
运行
复制
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)
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29631793

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档