Frage zu Zipfile

Hier werden alle anderen GUI-Toolkits sowie Spezial-Toolkits wie Spiele-Engines behandelt.
Antworten
patmaster
User
Beiträge: 106
Registriert: Donnerstag 3. Februar 2011, 17:21

Hi zusammen,

ich habe ein ZIP-Archiv das eine Ordnerstruktur und weitere Archive enthält.
Nun will ich nur bestimmte Archive entpacken, was auch wunderbar klappt mit diesem Code:

Code: Alles auswählen

import glob, zipfile
for file in glob.glob("R:\\Produktion\\Cases\\input\\*.xml"):
    filename = str(os.path.split(file)[1]).replace('.xml', '.zip')
    ziplist = zipfile.ZipFile("E:\\20110510.zip", "r")
    for member in zipfile.ZipFile.namelist(ziplist):
        if str(member).__contains__(filename):
            ziplist.extract(member, "E:\\")
Es werden zwar die richtigen files extrahiert, nur leider wird auch die Ordnerstruktur für die files angelegt.
Kann ich das iwie verhindern ?!
Zuletzt geändert von Anonymous am Dienstag 19. Juli 2011, 09:43, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
BlackJack

@patmaster: Da liegt aber ein bisschen was im Argen was das Verständnis von Python angeht. Und die Namensgebung ist auch nicht besonders gut.

`file` ist der Name eines eingebauten Typs, den sollte man nicht an etwas anderes binden. Zudem das was `glob()` liefert ja gar keine Datei-Objekte sind, sondern Zeichenketten die Pfade darstellen.

Sämtliche `str()`-Aufrufe in dem Quelltextschnippsel sollten überflüssig sein, weil es sich bei den Argumenten bereits um Zeichenketten handelt.

Der `replace()`-Aufruf auf dem Dateinamen kann Probleme bereiten, wenn '.xml' nicht nur als Endung, sondern auch *im* Namen vorkommt.

`ziplist` ist ein irreführender Name, weil es sich gar nicht um eine Liste, sondern um ein `ZipFile`-Objekt handelt.

Was soll ``zipfile.ZipFile.namelist(ziplist)``? Warum rufst Du da nicht die Methode auf `ziplist` auf? Und warum verwendest Du bei ``str(member).__contains__(filename)`` nicht den ``in``-Operator? Die ”magischen” Methoden sollte man eigentlich nur direkt aufrufen, wenn es keine andere Möglichkeit gibt. Wobei ``in`` genau wie bei dem `replace()` Probleme bereiten kann. Du willst ja nicht wissen ob der Name irgendwo *in* dem Pfad vorkommt, sondern ob er damit *endet*. Dann solltest Du auch nur das überprüfen.

Zum Pfad-Problem: Da wirst Du das auslesen aus dem Archiv und das schreiben in eine Datei selber implementieren müssten.
patmaster
User
Beiträge: 106
Registriert: Donnerstag 3. Februar 2011, 17:21

Ich habe erst vor kurzem mit Python begonnen. Da ich es aber schon einsetzen muss/will pfusche ich da noch etwas.
das file auch ein typ ist war mir nicht bekannt.

Diese casterei mit String mach ich irgendwie immer zur Sicherheit...stimmt könnte ich lassen.

Ich bin mir sicher das im file namen nirgends "xml" vorkommt, sonst hätte ich das natürlich anders gelöst.

ziplist heißt es weil es mal ne Liste war...hätte ich umbenennen sollen.

Warum ich die Methode nicht gleich aus ziplist aufrufe ist mir auch grad schleierhaft...echt weird.

Der in-Operator war mir noch nicht bekannt.

Danke für die ganzen Tipps :D
BlackJack

@patmaster: Deswegen sollte man möglichst vermeiden konkrete Typen im Namen zu erwähnen. Wenn man den Typen mal ändert, muss man auch den Namen überall anpassen, oder man hat einen irreführenden Namen im Programm. Ungetestet:

Code: Alles auswählen

import os
from glob import glob
from zipfile import ZipFile


CASES_PATH = r'R:\Produktion\Cases\input'
ARCHIVE_PATH = r'E:\20110510.zip'
EXTRACT_PATH = r'E:'


for path in glob(os.path.join(CASES_PATH, '*.xml')):
    filename = os.path.splitext(os.path.basename(path))[0] + '.zip'
    zip_file = ZipFile(ARCHIVE_PATH)
    for member in zip_file.namelist():
        if member.endswith(filename):
            data = zip_file.read(name)
            with open(os.path.join(EXTRACT_PATH, filename), 'wb') as out_file:
                out_file.write(data)
            break
Wobei mir der Algorithmus etwas ineffizient vorkommt. Für jede XML-Datei wird immer linear die Namensliste des ZIP-Archivs eingelesen und durchsucht.
patmaster
User
Beiträge: 106
Registriert: Donnerstag 3. Februar 2011, 17:21

Ich war gerade noch am Doku lesen da hattest du es schon fertig ^^

Funzt wunderbar....Vielen Dank !

Einziger Fehler

Code: Alles auswählen

data = zip_file.read(name)
muss

Code: Alles auswählen

data = zip_file.read(member)
heissen ;)

Darf man fragen warum du "splitext" und "basename" statt "split" verwendest ?!
BlackJack

@patmaster: `splitext()` und `basename()` machen genau das was man an der Stelle braucht. Warum sollte man sie nicht verwenden? `splitext()` kann man gar nicht durch `os.path.split()` ersetzen, und ``os.path.basename(p)`` sagt IMHO verständlicher was da passiert, als ``os.path.split(p)[1]``. Insbesondere für Leute die wissen was das Unix-Kommando ``basename`` macht.
patmaster
User
Beiträge: 106
Registriert: Donnerstag 3. Februar 2011, 17:21

Ich seh schon das du dir das replace später ersparst weil du den filenamen ohne extension bekommst...hatte ich vorher nicht gerafft.

Is mir gerade aufgefallen auf python.org:
Note that the result of this function is different from the Unix basename program; where basename for '/foo/bar/' returns 'bar', the basename() function returns an empty string ('').
Hast du vermutlich gewusst aber ich dachte ich poste es...

Danke noch mal für die Hilfe !
lunar

@patmaster: In diesem Fall ist das irrelevant, da man durch die Art des "glob()" sicher sein kann, dass keine Schrägstriche am Ende stehen. Ansonsten kann man Pfade mit "os.path.normpath()" in eine normalisierte Darstellung umwandeln, in der keine Schrägstriche am Ende stehen.
Antworten