从 zip 文件中解压缩选定的文件

Posted

技术标签:

【中文标题】从 zip 文件中解压缩选定的文件【英文标题】:Unzipping selected files from a zip file 【发布时间】:2021-05-25 13:49:00 【问题描述】:

我有一个内部文件夹结构为的 zip 文件:

CODE
`-- CODE
    `-- CODE
        `-- CODE
            |-- 2019
            |   |-- file1.txt
            |   `-- file2.txt
            |-- 2020
            |   `-- file3.txt
            `-- 2021
                |-- file4.txt
                `-- file5.txt

我想解压缩文件夹结构中的文件,如下所示:

CODE
|-- 2019
|   |-- file1.txt
|   `-- file2.txt
|-- 2020
|   `-- file3.txt
`-- 2021
    |-- file4.txt
    `-- file5.txt

我可以对其进行硬编码,但是,因为它是一个重复请求,我是否可以通过编程方式处理它以仅解压缩其中包含文件的文件夹。

我当前的代码是:

def unzipfiles(incoming_path):
    for path,subdirs,files in os.walk(incoming_path):
        for name in files:
            if(name.endswith('.zip')):
                with zipfile.ZipFile(os.path.join(incoming_path,name), 'r') as zip_ref:
                    for file in zip_ref.namelist():
                        out_path=os.path.join(incoming_path,file)
                        out_path=out_path.replace('CODE/','')
                        if(out_path[:-1]!=incoming_path):
                            zip_ref.extract(file,out_path)

但是,它无法正常工作,并且创建的文件夹比 zip 文件中的文件夹多。

【问题讨论】:

如果我理解正确的话,你想解压一个文件,然后删除其中的任何目录,它只包含另一个目录? 没错。 我可以假设目录名称是重复的,和/或包含数据的第一个文件夹是年号吗?换句话说,文件夹CODE的命名是否与zipfile名称以及所有其他子目录一致? 是的。我创建了一个对我有用的新功能。我已将代码粘贴到答案中。 【参考方案1】:

此代码对我有用。

def removeEmptyFolders(path, removeRoot=True):
  if not os.path.isdir(path):
    return
  files = os.listdir(path)
  if len(files):
    for f in files:
      fullpath = os.path.join(path, f)
      if os.path.isdir(fullpath):
        removeEmptyFolders(fullpath)
  files = os.listdir(path)
  if len(files) == 0 and removeRoot:
    os.rmdir(path)

【讨论】:

【参考方案2】:

我使用的解决方案是将文件的完整路径映射到一个相对较短的名称。对于解决方案,我将采用 OP 提供的 zip 结构。

import os
import re
import pathlib
import shutil
import zipfile
from pprint import pprint

if __name__ == '__main__':
    toplevel = os.path.join('files')
    new_structure = dict()

    # Let's just extract everything
    with zipfile.ZipFile('CODE.zip', 'r') as zip_file:

        for zip_info in zip_file.infolist():
            path = pathlib.PurePath(zip_info.filename)

            # This writes the data from the old file to a new file.
            if str(path.parent) in new_structure:
                source = zip_file.open(zip_info)
                target = open(os.path.join(new_structure[str(path.parent)], path.name), "wb")

                with source, target:
                    shutil.copyfileobj(source, target)

            # Create the new folder structure mapping, based on the year name.
            # The matches are based on numbers in this example, but can be specified.
            if re.match('\d+', path.name):  
                new_structure[str(path)] = os.path.join(toplevel, path.name)
                os.makedirs(new_structure[str(path)], exist_ok=True)

    pprint(new_structure)

输出 (pprint),显示重映射结构:

'CODE\\CODE\\CODE\\CODE\\2019': 'files\\2019',
 'CODE\\CODE\\CODE\\CODE\\2020': 'files\\2020',
 'CODE\\CODE\\CODE\\CODE\\2021': 'files\\2021'

输出是一个具有以下结构的新文件夹:

files
|-- 2019
|   |-- file1.txt
|   `-- file2.txt
|-- 2020
|   `-- file3.txt
`-- 2021
    |-- file4.txt
    `-- file5.txt

注意事项

有两点很有趣:

    正则表达式模式匹配用于确定文件路径'\d+',它只接受数字列表,如果您想更精确,可以使用\d4 精确匹配四位数字。

    此方法只假设一个较低的级别,也就是说,多个嵌套文件将无法正确解包。为此,if str(path.parent) in new_structure: 行必须更改以考虑多个父路径。

【讨论】:

以上是关于从 zip 文件中解压缩选定的文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中解压缩多层 zip 文件

如何从多个 tar 文件中解压缩特定文件并压缩它们?

如何在 HDFS 中解压缩多个 zip 文件

如何在iOS中解压缩异步方式的zip文件?

如何在php中解压缩zip文件[重复]

xml 在java中解压缩一个zip文件。