Как извлечь 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)
.