【问题标题】:Unzipping selected files from a zip file从 zip 文件中解压缩选定的文件
【发布时间】: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名称以及所有其他子目录一致?
  • 是的。我创建了一个对我有用的新功能。我已将代码粘贴到答案中。

标签: python python-3.x 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
    

    注意事项

    有两点很有趣:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多