zwei Dateien in ein Zipfile schreiben

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
tz_wuerzburg
User
Beiträge: 71
Registriert: Dienstag 7. März 2017, 17:51

Hallo liebe Forumsmitglieder,
ich nutze das zipfile Modul und möchte zwei Dateien in ein neu erstelltes Zipfile schreiben.
Das ganze funktioniert auch ganz gut, dass Problem ist nur, dass eins der beiden Files mit dem kompletten Pfad in das Zipfile
geschrieben wird.

Code: Alles auswählen

def zip(import_original):
    original_del_txt = import_original[:-4]
    zip_filename = "ready_" + original_del_txt + ".zip"
    zip_daten_pfad = Path("xml/daten/")
    zip_speicher_name = zip_daten_pfad / zip_filename
    zipfile_erstellen = zipfile.ZipFile(zip_speicher_name, 'w', zipfile.ZIP_DEFLATED)
    txt_file = "ready_" + import_original
    xml_file = zip_xml_name()
    zipfile_erstellen.write(txt_file)
    zipfile_erstellen.write(xml_file)
    
    
 def zip_xml_name():
    haupt_pfad = Path("xml/daten/")
    xml_name_file = haupt_pfad / "zipfile_name.txt"
    daten_pfad = Path("xml/daten/")
    with open(xml_name_file, "r", encoding="utf-8") as filename_import:
        eingabe = csv.reader(filename_import, delimiter="\t")
        for zaehler, zeile in enumerate(eingabe):
            if zaehler == 0:
                xml_file_name = daten_pfad / zeile[0]
                return(xml_file_name)

zip(import_original)
Das txt File wird ordentlich in die Datei geschrieben, das xml File mit der Struktur xml/daten/xml_file.
Wie bekomme ich das xml File in die erste Ebene?

Danke Euch!
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@tz_wuerzburg: die Namensgebung ist verwirrend für mich. `zipfile_erstellen` ist ein Name für eine Funktion. Dass dreimal `xml/daten/` vorkommt, ist schlecht, weil man Dopplungen vermeiden sollte. Solche Konstanten sollten auch als Konstanten am Anfang des Programms geschrieben werden.
Die Funktionsnamen dagegen sind eigentlich Variablennamen, weil sie keine Tätigkeit beschreiben (`zip` ist egal wie, zu kurz). zip_xml_name hieße besser `ermittle_xml_dateiname`.
import_original ist auch ein schlechter Name, weil ja nichts importiert wird. `quell_textdateiname` wäre klarer, dann weiß ich wenigstens, dass es sich um die Text-Datei handelt, die aber im aktuellen Verzeichnis liegen muß, was bei einer Funktion keine gute Voraussetzung ist, wenn man sie flexibel einsetzen will.
Bei Zip-Dateien ist es besonders wichtig, dass sie ordentlich geschlossen werden, weil noch ein Verzeichnis ans Ende der Datei geschrieben wird, daher immer mit with öffnen.
Dass dann das Ergebnis so ähnlich heißt wie die übergebene Textdatei in einem relativ dazu liegenden Pfad gespeichert wird und auch noch eine xml-Datei mit ähnlichem Namen existiert, macht die Funktion quasi unmöglich zu verändern und korrekt zu verwenden. Diese ganze Information mag zwar im Kontext Deines Problems korrekt sein, aber das als Bedingung für eine Funktion implizit zu fordern, ist nicht gut, weil zu versteckt.

In `zip_xml_name` steht ein `return` in einer for-Schleife, das immer beim ersten Schleifendurchlauf die Schleife beendet, und das noch ziemlich kompliziert formuliert.

Beim jetzt nochmal durchlesen, sehe ich, dass quell_textdateiname gar nicht der Name der Text-Datei ist, die in die ZIP-Datei geschrieben wird, sondern die eigentliche Datei hat noch ein ready_ davor.

Wenn ich alles richtige entschlüsselt habe, komme ich bei sowas raus:

Code: Alles auswählen

RELATIVE_XML_DATEN_PATH = Path("xml/daten/")
ZIP_FILENAMES_FILENAME = RELATIVE_XML_DATEN_PATH / "zipfile_name.txt"
READY_TEXT_FILENAME_PATTERN = "ready_{0.name}"
READY_ZIP_FILENAME_PATTERN = "ready_{0.stem}.zip"

def get_first_filename(filenames_filename):
    """ reads the first filename of a file named filenames_filename
    and returns this filename relative to the directory where filenames_filename
    lies"""
    with open(filenames_filename, encoding="utf-8") as lines:
        filenames = csv.reader(lines, delimiter="\t")
        return filenames_filename.parent / next(filenames)[0]

def write_zip_file(source_filename):
    """ writes a zip file with
    needs special directory structure at the place where source_filename lives"""
    basepath = source_filename.parent
    text_filename = basepath / READY_TEXT_FILENAME_PATTERN.format(source_filename)
    zip_filename = basepath / RELATIVE_XML_DATEN_PATH / READY_ZIP_FILENAME_PATTERN.format(source_filename)
    xml_filename = get_first_filename(basepath / ZIP_FILENAMES_FILENAME)
    with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as archive:
        archive.write(text_filename, text_filename.name)
        archive.write(xml_filename, xml_filename.name)
tz_wuerzburg
User
Beiträge: 71
Registriert: Dienstag 7. März 2017, 17:51

Wow! Vielen Dank für die Hilfe!
Deinen Code habe ich leider nicht ganz verstanden, aber es ist dann doch einiges eingeflossen (es funktionert jetzt).

- die Pfade wurden für das komplette Projekt festgelegt
- die Funktions- und Variablennamen wurden angepasst
- die Zipdatei wird geschlossen

Code: Alles auswählen

hauptverzeichnis = Path("xml/")
daten = Path("xml/daten/")

def xml_name_auslesen(hauptverzeichnis, daten):
    xml_file_pfad = hauptverzeichnis / "zipfile_name.txt"
    with open(xml_file_pfad, "r", encoding="utf-8") as filename_import:
        dateiname = csv.reader(filename_import, delimiter="\t")
        return daten / next(dateiname)[0]

def zipfile_erstellen(import_original_dateiname, hauptverzeichnis, daten):
    zipfile_name_generieren = "ready_" + import_original_dateiname[:-4]  + ".zip"
    zip_speicher_name = daten / zipfile_name_generieren
    txt_filename = "ready_" + import_original_dateiname
    xml_filename = xml_name_auslesen(hauptverzeichnis, daten)
    with zipfile.ZipFile(zip_speicher_name, 'w', zipfile.ZIP_DEFLATED) as archive:
        archive.write(txt_filename)
        archive.write(xml_filename, xml_filename.name)

zipfile_erstellen(import_original_dateiname, hauptverzeichnis, daten)

Folgende Punkte habe ich nicht verstanden:

Code: Alles auswählen

 archive.write(xml_filename, xml_filename.name)
Es wird erst der komplette Pfad gelesen und dann doch nur die Datei geschrieben. Dieser Punkt behebt ja mein
eigentliches Problem.

Code: Alles auswählen

READY_TEXT_FILENAME_PATTERN = "ready_{0.name}"
READY_ZIP_FILENAME_PATTERN = "ready_{0.stem}.zip"
Warum 0.name und 0.stem?
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Statt wieder mit + Strings zusammenzustückeln und mit Slicing die Endung abzuschneiden und immer noch mit fixen relativen Pfaden zu arbeiten, solltest Du das, was ich geschrieben habe versuchen zu verstehen und sonst hier nachfragen.

Die 0 in format-Strings bezieht sich auf das 0te Argument.
Und wie der write-Aufruf von Zipfile funktioniert, kannst Du einfach in der Dokumentation nachlesen.
Antworten