web-dev-qa-db-fra.com

Comment lire à partir d'un fichier Zip dans un fichier Zip en Python?

J'ai un fichier que je veux lire qui est lui-même compressé dans une archive Zip. Par exemple, parent.Zip contient child.Zip, qui contient child.txt. J'ai du mal à lire child.Zip. Quelqu'un peut-il corriger mon code?

Je suppose que je dois créer child.Zip en tant qu'objet de type fichier, puis l'ouvrir avec une seconde instance de zipfile, mais être nouveau dans python mon zipfile.ZipFile (zfile.open (nom)) est stupide. Il soulève un fichier zip.BadZipfile: "Le fichier n'est pas un fichier Zip" sur child.Zip (validé indépendamment)

import zipfile
with zipfile.ZipFile("parent.Zip", "r") as zfile:
    for name in zfile.namelist():
        if re.search(r'\.Zip$', name) != 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"
29
Michael Collinson

Lorsque vous utilisez l'appel .open() sur une instance ZipFile, vous obtenez en effet un descripteur de fichier ouvert. Cependant, pour lire un fichier Zip, la classe ZipFile a besoin d’un peu plus. Il doit être capable de chercher sur ce fichier, et l'objet renvoyé par .open() n'est pas cherchable.

La solution consiste à lire l'intégralité de l'entrée Zip en mémoire à l'aide de .read(), à la stocker dans un objet BytesIO (un fichier en mémoire qui est à rechercher) et à l'envoyer à ZipFile

from io import BytesIO

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

ou, dans le contexte de votre exemple:

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) != None:
            # We have a Zip within a Zip
            zfiledata = BytesIO(zfile.read(name))
            with zipfile.ZipFile(zfiledata) as zf
                for name2 in zfile2.namelist():
                    # Now we can extract
                    logging.info( "Found internal internal file: " + name2)
                    print "Processing code goes here"
39
Martijn Pieters

Pour que cela fonctionne avec python33 (sous Windows mais cela pourrait ne pas être pertinent), je devais faire:

 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 n'existe pas alors j'ai utilisé io.BytesIO

8
zlr

Voici une fonction que je suis venu avec. (Copié de ici .)

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)

Voici comment je l'ai testé:

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()
0
Matt Faus