Как читать из zip-файла внутри zip-файла в Python?

python file zip unzip

16397 просмотра

3 ответа

166 Репутация автора

У меня есть файл, который я хочу прочитать, который сам заархивирован в zip-архиве. Например, parent.zip содержит child.zip, который содержит child.txt. У меня проблемы с чтением child.zip. Кто-нибудь может исправить мой код?

Я предполагаю, что мне нужно создать child.zip как подобный файлу объект и затем открыть его со вторым экземпляром zipfile, но, будучи новичком в python, мой zipfile.ZipFile (zfile.open (name)) глупо. Это поднимает zipfile.BadZipfile: «Файл не является zip-файлом» на (независимо проверенном) child.zip

import zipfile
with zipfile.ZipFile("parent.zip", "r") as zfile:
    for name in zfile.namelist():
        if re.search(r'\.zip$', name) is not None:
            # We have a zip within a zip
            with **zipfile.ZipFile(zfile.open(name))** as zfile2:
                    for name2 in zfile2.namelist():
                        # Now we can extract
                        logging.info( "Found internal internal file: " + name2)
                        print "Processing code goes here"
Автор: Michael Collinson Источник Размещён: 19.08.2012 09:19

Ответы (3)


45 плюса

772561 Репутация автора

Решение

Когда вы используете .open()вызов ZipFileэкземпляра, вы действительно получаете дескриптор открытого файла. Однако, чтобы прочитать zip-файл, ZipFileклассу нужно немного больше. Он должен иметь возможность поиска по этому файлу, а возвращаемый объект .open()не может быть найден в вашем случае. Только Python 3 (3.2 и выше) создает ZipExFileобъект, который поддерживает поиск (при условии, что основной дескриптор файла для внешнего zip-файла является доступным для поиска, и ничто не пытается записать в ZipFileобъект).

Чтобы обойти эту проблему , чтобы прочитать всю запись почтового индекса в памяти , используя .read(), хранить его в BytesIOобъект (файл в памяти , что является доступной для поиска) и корма , что ZipFile:

from io import BytesIO

# ...
        zfiledata = BytesIO(zfile.read(name))
        with zipfile.ZipFile(zfiledata) as zfile2:

или, в контексте вашего примера:

import zipfile
from io import BytesIO

with zipfile.ZipFile("parent.zip", "r") as zfile:
    for name in zfile.namelist():
        if re.search(r'\.zip$', name) is not None:
            # We have a zip within a zip
            zfiledata = BytesIO(zfile.read(name))
            with zipfile.ZipFile(zfiledata) as zfile2:
                for name2 in zfile2.namelist():
                    # Now we can extract
                    logging.info( "Found internal internal file: " + name2)
                    print "Processing code goes here"
Автор: Martijn Pieters Размещён: 19.08.2012 09:25

9 плюса

620 Репутация автора

Чтобы заставить это работать с python33 (под окнами, но это может быть неактуально), мне нужно было сделать:

 import zipfile, re, io
    with zipfile.ZipFile(file, 'r') as zfile:
        for name in zfile.namelist():
            if re.search(r'\.zip$', name) != None:
                zfiledata = io.BytesIO(zfile.read(name))
                with zipfile.ZipFile(zfiledata) as zfile2:
                    for name2 in zfile2.namelist():
                        print(name2)

cStringIO не существует, поэтому я использовал io.BytesIO

Автор: zlr Размещён: 20.11.2013 02:57

0 плюса

4772 Репутация автора

Вот функция, которую я придумал. (Скопировано здесь .)

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()
Автор: Matt Faus Размещён: 12.06.2014 08:58
Вопросы из категории :
32x32