Как извлечь zip-файл рекурсивно в Python

у меня есть zip-файл, который содержит три zip-файлы в так:

zipfile.zip  
    dirA.zip
         a  
    dirB.zip
         b  
    dirC.zip
         c

Я хочу извлечь все внутренние zip-файлы, которые находятся внутри zip-файла в каталогах с этими именами (dirA, dirB, dirC).
В принципе, я хочу получить следующую схему:

output  
    dirA
         a  
    dirB
         b  
    dirC
         c

я попробовал следующее:

import os, re
from zipfile import ZipFile

os.makedirs(directory)  # where directory is "output"
with ZipFile(self.archive_name, "r") as archive:
    for id, files in data.items():
        if files:
            print("Creating", id)
            dirpath = os.path.join(directory, id)

            os.mkdir(dirpath)

            for file in files:
                match = pattern.match(filename)
                new = match.group(2)
                new_filename = os.path.join(dirpath, new)

                content = archive.open(file).read()
            with open(new_filename, "wb") as outfile:
                outfile.write(content)

но он извлекает только zip-файл, и я заканчиваю:

output  
    dirA
         dirA.zip 
    dirB
         dirB.zip 
    dirC
         dirC.zip

любой предложения, в том числе код-сегменты будет очень признателен, потому что я пробовал так много разных вещей и читал документы без успеха.

3 ответов


при извлечении zip-файла вы захотите записать внутренние zip-файлы в память, а не на диск. Для этого я использовал BytesIO.

проверьте этот код:

import os
import io
import zipfile

def extract(filename):
    z = zipfile.ZipFile(filename)
    for f in z.namelist():
        # get directory name from file
        dirname = os.path.splitext(f)[0]  
        # create new directory
        os.mkdir(dirname)  
        # read inner zip file into bytes buffer 
        content = io.BytesIO(z.read(f))
        zip_file = zipfile.ZipFile(content)
        for i in zip_file.namelist():
            zip_file.extract(i, dirname)

если вы запустите extract("zipfile.zip") С zipfile.zip as:

zipfile.zip/
    dirA.zip/
        a
    dirB.zip/
        b
    dirC.zip/
        c

вывод должен быть:

dirA/
  a
dirB/
  b
dirC/
  c

для функции, которая извлекает вложенный zip-файл (любой уровень вложенности) и очищает исходные zip-файлы:

import zipfile, re, os

def extract_nested_zip(zippedFile, toFolder):
    """ Extract a zip file including any 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)

я попробовал некоторые другие решения, но не смог заставить их работать "на месте". Я опубликую свое решение для обработки версии "на месте". Примечание:Он удаляет zip-файлы и "заменяет" их одинаково названными каталогами, так что резервное копирование zip-файлов, если вы хотите сохранить.

стратегия проста. Распакуйте все zip-файлы в каталоге (и подкаталогах) и промойте и повторите, пока не останутся zip-файлы. Полоскание и повторение необходимо, если zip-файлы содержащие сжатый файл.

def unzip_directory(directory):
    """" This function unzips (and then deletes) all zip files in a directory """
    for root, dirs, files in os.walk(directory):
        for filename in files:
            if re.search(r'\.zip$', filename):
                to_path = os.path.join(root, filename.split('.zip')[0])
                zipped_file = os.path.join(root, filename)
                if not os.path.exists(to_path):
                    os.makedirs(to_path)
                    with zipfile.ZipFile(zipped_file, 'r') as zfile:
                        zfile.extractall(path=to_path)
                    # deletes zip file
                    os.remove(zipped_file)

def exists_zip(directory):
    """ This function returns T/F whether any .zip file exists within the directory, recursively """
    is_zip = False
    for root, dirs, files in os.walk(directory):
        for filename in files:
            if re.search(r'\.zip$', filename):
                is_zip = True
    return is_zip

def unzip_directory_recursively(directory, max_iter=1000):
    """ Calls unzip_directory until all contained zip files (and new ones from previous calls)
    are unzipped
    """
    iterate = 0
    while exists_zip(directory) and iterate < max_iter:
        unzip_directory(directory)
        iterate += 1
    pre = "Did not " if iterate < max_iter else "Did"
    print(pre, "time out based on max_iter limit of", max_iter, ". Took iterations:", iterate)

предполагая, что ваши zip-файлы скопированы, вы делаете все это, вызывая unzip_directory_recursively(your_directory).