【问题标题】:Unzip nested zip files in python在python中解压缩嵌套的zip文件
【发布时间】:2012-08-13 08:20:28
【问题描述】:

我正在寻找一种在 python 中解压缩嵌套 zip 文件的方法。例如,考虑以下结构(为方便起见,假设名称):

  • 文件夹
    • ZipfileA.zip
      • ZipfileA1.zip
      • ZipfileA2.zip
    • ZipfileB.zip
      • ZipfileB1.zip
      • ZipfileB2.zip

...等等。我正在尝试访问第二个 zip 中的文本文件。我当然不想提取所有内容,因为剪切数字会使计算机崩溃(第一层有几百个拉链,第二层有近 10,000 个拉链(每个拉链))。

我一直在使用“zipfile”模块——我能够打开第一级 zipfile。例如:

zipfile_obj = zipfile.ZipFile("/Folder/ZipfileA.zip")
next_layer_zip = zipfile_obj.open("ZipfileA1.zip")

但是,这会返回一个“ZipExtFile”实例(不是文件或 zipfile 实例)——然后我无法继续打开这个特定的数据类型。我不能这样做:

data = next_layer_zip.open(data.txt)

但是,我可以通过以下方式“读取”这个 zip 文件:

next_layer_zip.read()

但这完全没用! (即只能读取压缩数据/goobledigook)。

有没有人对我如何解决这个问题有任何想法(没有使用 ZipFile.extract)?

我遇到了这个,http://pypi.python.org/pypi/zip_open/ - 它看起来完全符合我的要求,但它似乎对我不起作用。 (对于我正在尝试处理的文件,使用该模块继续获取“[Errno 2] No such file or directory:”)。

任何想法将不胜感激!提前致谢

【问题讨论】:

    标签: python zip


    【解决方案1】:

    ZipFile 需要一个类似文件的对象,因此您可以使用 StringIO 将您从嵌套 zip 读取的数据转换为这样的对象。需要注意的是,您会将完整的(仍然压缩的)内部 zip 加载到内存中。

    with zipfile.ZipFile('foo.zip') as z:
        with z.open('nested.zip') as z2:
            z2_filedata = cStringIO.StringIO(z2.read())
            with zipfile.ZipFile(z2_filedata) as nested_zip:
                print nested_zip.open('data.txt').read()
    

    【讨论】:

      【解决方案2】:

      不幸的是,解压缩 zip 文件需要随机访问存档,而 ZipFile 方法(更不用说 DEFLATE 算法本身)只提供流。因此,不解压缩嵌套的 zip 文件是不可能的。

      【讨论】:

        【解决方案3】:

        这是我想出的一个功能。

        def extract_nested_zipfile(path, parent_zip=None):
            """Returns a ZipFile specified by path, even if the path contains
            intermediary ZipFiles.  For example, /root/gparent.zip/parent.zip/child.zip
            will return a ZipFile that represents child.zip
            """
        
            def extract_inner_zipfile(parent_zip, child_zip_path):
                """Returns a ZipFile specified by child_zip_path that exists inside
                parent_zip.
                """
                memory_zip = StringIO()
                memory_zip.write(parent_zip.open(child_zip_path).read())
                return zipfile.ZipFile(memory_zip)
        
            if ('.zip' + os.sep) in path:
                (parent_zip_path, child_zip_path) = os.path.relpath(path).split(
                    '.zip' + os.sep, 1)
                parent_zip_path += '.zip'
        
                if not parent_zip:
                    # This is the top-level, so read from disk
                    parent_zip = zipfile.ZipFile(parent_zip_path)
                else:
                    # We're already in a zip, so pull it out and recurse
                    parent_zip = extract_inner_zipfile(parent_zip, parent_zip_path)
        
                return extract_nested_zipfile(child_zip_path, parent_zip)
            else:
                if parent_zip:
                    return extract_inner_zipfile(parent_zip, path)
                else:
                    # If there is no nesting, it's easy!
                    return zipfile.ZipFile(path)
        

        这是我的测试方法:

        echo hello world > hi.txt
        zip wrap1.zip hi.txt
        zip wrap2.zip wrap1.zip
        zip wrap3.zip wrap2.zip
        
        print extract_nested_zipfile('/Users/mattfaus/dev/dev-git/wrap1.zip').open('hi.txt').read()
        print extract_nested_zipfile('/Users/mattfaus/dev/dev-git/wrap2.zip/wrap1.zip').open('hi.txt').read()
        print extract_nested_zipfile('/Users/mattfaus/dev/dev-git/wrap3.zip/wrap2.zip/wrap1.zip').open('hi.txt').read()
        

        【讨论】:

        • 对于那些使用 3.3 的人,为了节省您一些时间 TypeError: string argument expected, got 'bytes'memory_zip.write(parent_zip.open(child_zip_path).read()) 行相关的不确定解决方法
        【解决方案4】:

        我使用 python 3.7.3

        import zipfile
        import io
        with zipfile.ZipFile('all.zip') as z:
            with z.open('nested.zip') as z2:
                z2_filedata =  io.BytesIO(z2.read())
                with zipfile.ZipFile(z2_filedata) as nested_zip:
                    print( nested_zip.open('readme.md').read())
        

        【讨论】:

          【解决方案5】:

          对于那些寻求提取嵌套 zip 文件(任何级别的嵌套)并清理原始 zip 文件的功能的人:

          import zipfile, re, os
          
          def extract_nested_zip(zippedFile, toFolder):
              """ Unzip a zip file and its contents, including nested zip files
                  Delete the zip file(s) after extraction
              """
              with zipfile.ZipFile(zippedFile, 'r') as zfile:
                  zfile.extractall(path=toFolder)
              os.remove(zippedFile)
              for root, dirs, files in os.walk(toFolder):
                  for filename in files:
                      if re.search(r'\.zip$', filename):
                          fileSpec = os.path.join(root, filename)
                          extract_nested_zip(fileSpec, root)
          

          【讨论】:

            【解决方案6】:

            这对我有用。只需将此脚本与嵌套 zip 放在同一目录下即可。它还将计算嵌套 zip 中的文件总数

            import os
            
            from zipfile import ZipFile
            
            
            def unzip (path, total_count):
                for root, dirs, files in os.walk(path):
                    for file in files:
                        file_name = os.path.join(root, file)
                        if (not file_name.endswith('.zip')):
                            total_count += 1
                        else:
                            currentdir = file_name[:-4]
                            if not os.path.exists(currentdir):
                                os.makedirs(currentdir)
                            with ZipFile(file_name) as zipObj:
                                zipObj.extractall(currentdir)
                            os.remove(file_name)
                            total_count = unzip(currentdir, total_count)
                return total_count
            
            total_count = unzip ('.', 0)
            print(total_count)
            

            【讨论】:

              【解决方案7】:

              我解决此类问题的方法是这样的,包括自分配对象:

              import os
              import re 
              import zipfile
              import pandas as pd
              # import numpy as np
              path = r'G:\Important\Data\EKATTE'
              
              # DESCRIBE
              archives = os.listdir(path)
              archives = [ar for ar in archives if ar.endswith(".zip")]
              contents = pd.DataFrame({'elec_date':[],'files':[]})
              for a in archives:
                  archive = zipfile.ZipFile( path+'\\'+a )
                  filelist = archive.namelist()
                  # archive.infolist()
                  for i in archive.namelist():
                      if re.match('.*zip', i):
                          sub_arch = zipfile.ZipFile(archive.open(i))
                          sub_names = [x for x in sub_arch.namelist()]
                          for s in sub_names:
                              exec(f"{s.split('.')[0]} = pd.read_excel(sub_arch.open(s), squeeze=True)")
              

              存档可在保加利亚国家统计局页面(直接链接)上找到: https://www.nsi.bg/sites/default/files/files/EKATTE/Ekatte.zip

              【讨论】:

                猜你喜欢
                • 2017-05-24
                • 2021-05-29
                • 2020-11-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-08-03
                • 1970-01-01
                相关资源
                最近更新 更多