Wie simuliere ich ZipFile.open in Python 2.5?

Ich möchte eine Datei aus einer ZIP-Datei in einen bestimmten Pfad extrahieren und dabei den Dateipfad im Archiv ignorieren. Dies ist in Python 2.6 sehr einfach (mein Docstring ist länger als der Code)

import shutil
import zipfile

def extract_from_zip(name, dest_path, zip_file):
    """Similar to zipfile.ZipFile.extract but extracts the file given by name
    from the zip_file (instance of zipfile.ZipFile) to the given dest_path
    *ignoring* the filename path given in the archive completely
    instead of preserving it as extract does.
    """
    dest_file = open(dest_path, 'wb')
    archived_file = zip_file.open(name)
    shutil.copyfileobj(archived_file, dest_file)


 extract_from_zip('path/to/file.dat', 'output.txt', zipfile.ZipFile('test.zip', 'r'))

Aber in Python 2.5, The ZipFile.open -Methode ist nicht verfügbar. Ich konnte keine Lösung für den Stackoverflow finden, aberdieser Forumsbeitrag hatte eine schöne Lösung, die das @ nutZipInfo.file_offset, um nach der richtigen Stelle im Zip zu suchen und @ zu verwendzlib.decompressobj, um die Bytes von dort zu entpacken. UnglücklicherweiseZipInfo.file_offset wurde in Python 2.5 entfernt!

So, da wir in Python 2.5 nur das @ habZipInfo.header_offset, Ich dachte, ich müsste nur die Header-Struktur analysieren und überspringen, um selbst zum Datei-Offset zu gelangen. Wikipedia als @ verwendeine Referen (Ich weiß) Ich habe mir diese viel längere und nicht sehr elegante Lösung ausgedacht.

import zipfile
import zlib

def extract_from_zip(name, dest_path, zip_file):
    """Python 2.5 version :("""
    dest_file = open(dest_path, 'wb')
    info = zip_file.getinfo(name)
    if info.compress_type == zipfile.ZIP_STORED:
        decoder = None
    elif info.compress_type == zipfile.ZIP_DEFLATED:
        decoder = zlib.decompressobj(-zlib.MAX_WBITS)
    else:
        raise zipfile.BadZipFile("Unrecognized compression method")

    # Seek over the fixed size fields to the "file name length" field in
    # the file header (26 bytes). Unpack this and the "extra field length"
    # field ourselves as info.extra doesn't seem to be the correct length.
    zip_file.fp.seek(info.header_offset + 26)
    file_name_len, extra_len = struct.unpack("<HH", zip_file.fp.read(4))
    zip_file.fp.seek(info.header_offset + 30 + file_name_len + extra_len)

    bytes_to_read = info.compress_size

    while True:
        buff = zip_file.fp.read(min(bytes_to_read, 102400))
        if not buff:
            break
        bytes_to_read -= len(buff)
        if decoder:
            buff = decoder.decompress(buff)
        dest_file.write(buff)

    if decoder:
        dest_file.write(decoder.decompress('Z'))
        dest_file.write(decoder.flush())

Note, wie ich das Feld auspacke und lese, das die Länge des zusätzlichen Feldes angibt, weil der Aufruf vonlen auf derZipInfo.extra -Attribut ergibt 4 Bytes weniger, wodurch der Offset falsch berechnet wird. Vielleicht fehlt mir hier etwas?

Kann jemand diese Lösung für Python 2.5 verbessern?

Bearbeiten Ich hätte sagen sollen, die naheliegende Lösung wie von ChrisAdams vorgeschlagen

dest_file.write(zip_file.read(name))

wird fehlschlagen mitMemoryError für alle Dateien mit einer angemessenen Größe, die in der ZIP-Datei enthalten sind, da versucht wird, die gesamte Datei auf einmal in den Speicher zu kopieren. Ich habe große Dateien, daher muss ich den Inhalt auf die Festplatte streamen.

Auch ein Upgrade von Python ist die naheliegende Lösung, aber eine, die völlig aus meiner Hand liegt und im Grunde genommen unmöglich ist.

Antworten auf die Frage(6)

Ihre Antwort auf die Frage