Foderinhalt archivieren, zipfile anhand einträgen aus liste erstellen

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
tomrause
User
Beiträge: 12
Registriert: Freitag 26. Februar 2021, 19:20

Hallo zusammen.
Ich will folgende Aufgabe lösen:
einmal wöchentlich soll ein Verzeichnis, in dem täglich 140 bis 150 EDI-Files abgelegt werden, anhand des Aktualisierungsdatums in einem ZIP-File archviert werden. Damit soll bei nachträglichen Suchen nicht der unsortierte Datenwust manuell gesichtet werden, sondern nur noch ZIP-Files herangezogen werden müssen. Das ganze dann per Batch-Datei und Python-Skript, mit dem das archivieren automatisiert abläuft. Zur Zeit sind mehrere Tausend Dateien im Verzeichnis....

Der Plan:
Aktualisierungsdaten aller Files in eine Liste schreiben und dies mit set(datumsliste) eindeutig machen.
Diese Liste wird dann durclaufen und für jedes darin enthaltene Datum den Archivierungsvorgang mit vorgeschalteter Datei-Selektion ausführen.
... so der Plan.

Leider tritt dann der u.a. Fehler auf, der vermutlich aufgrund der Liste nicht funktioniert.
Was könnte ich am Plan ändern? Dictionary erzeugen und das abarbeiten (woerterbuch={'dateinangabe' : 'dateidatum'))?

Code: Alles auswählen

import os, datetime
from zipfile import ZipFile

#Funktion zum umformatieren des Aktualisierungsdatums in das Format JJJJMMTT
def format_gmtime_from_file(filename):
    modification_time = datetime.datetime.fromtimestamp(os.path.getmtime(filename))
    return f"{modification_time:%Y%m%d}"

#Dateiliste erstellen
def erstelle_dateiliste(akt_dat, pattern, quellpfad):
    files = os.listdir(quellpfad)
    filelist=[]
    for file in files:
        #print(file)
        if file[:6]==pattern:
            mod_date=format_gmtime_from_file(quellpfad + chr(92) + file)
            if mod_date==akt_dat:
                filelist.append(quellpfad +chr(92) + file)
    return filelist

#Dateiliste an ZIP zum archivieren übergeben
def archiviere_dateiliste(liste, archivpfaddatei):
    i=len(liste)
    with ZipFile(archivpfaddatei, 'w') as ergebnis_zip_datei:
   # Add multiple files to the zip
        for f in liste:
            ergebnis_zip_datei.write(liste)
        
        ergebnis_zip_datei.close
        
        return i

#Ab hier soll akt_dat aus der übergeordneten datumsliste "for datum in datumsliste:-Schleife abgearbeitet werden
akt_dat='20210102'
quellpfad=r'Z:\quelleverzeichnis'
muster='MUSTER'
archivpfaddatei=r'K:\zielverzeichnis'+chr(92) + akt_dat + chr(95) + muster + '.zip'

meineliste=erstelle_dateiliste(akt_dat,muster,quellpfad)
print(meineliste)
ergebnis=archiviere_dateiliste(meineliste,archivpfaddatei) #=> ab hier tritt dann der u.a. Fehler auf
print(ergebnis +' Datei(en) archiviert')


TypeError                                 Traceback (most recent call last)
<ipython-input-4-d3f36573b0ae> in <module>
      6 meineliste=erstelle_dateiliste(akt_dat,muster,quellpfad)
      7 print(meineliste)
----> 8 ergebnis=archiviere_dateiliste(meineliste,archivpfaddatei)
      9 print(ergebnis +' Datei(en) archiviert')

<ipython-input-2-c94b2ef3efd2> in archiviere_dateiliste(liste, archivpfaddatei)
     21    # Add multiple files to the zip
     22         for f in liste:
---> 23             ergebnis_zip_datei.write(liste)
     24 
     25         ergebnis_zip_datei.close

~\anaconda3\lib\zipfile.py in write(self, filename, arcname, compress_type, compresslevel)
   1739             )
   1740 
-> 1741         zinfo = ZipInfo.from_file(filename, arcname,
   1742                                   strict_timestamps=self._strict_timestamps)
   1743 

~\anaconda3\lib\zipfile.py in from_file(cls, filename, arcname, strict_timestamps)
    521         if isinstance(filename, os.PathLike):
    522             filename = os.fspath(filename)
--> 523         st = os.stat(filename)
    524         isdir = stat.S_ISDIR(st.st_mode)
    525         mtime = time.localtime(st.st_mtime

TypeError: stat: path should be string, bytes, os.PathLike or integer, not list
Ich bitte um Hinweise
Danke
Tom
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Benutze keine Abkürzung. Statt akt_dat heißt es aktuelles_datum. Was soll das meine bei meineliste? Gibt es auch eureliste? Besser wäre dateinamen, dann weiß man auch gleich, was denn in der Liste drin ist.
Warum chr(92)? Da muss doch jeder rätseln. Pfade stückelt man auch nicht mit + zusammen. Pfade sind keine Strings. Benutze pathlib.Path. Damit wird das Durchsuchen des Verzeichnisses auch viel einfacher.
Die Fehlermeldung ist eigentlich eindeutig, zumal du schon eine for-Schleife hast, das f aber gar nicht benutzt. close sollte man aufrufen oder besser gleich ganz weglassen, da du ja with hast.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Könnte so aussehen:

Code: Alles auswählen

import datetime
from zipfile import ZipFile
from pathlib import Path

AKTUELLES_DATUM = '20210102'
MUSTER = "MUSTER"
QUELLPFAD = Path('Z:/quelleverzeichnis')
ARCHIVPFAD = Path('K:/zielverzeichnis') / AKTUELLES_DATUM / MUSTER + '.zip'

def erstelle_dateiliste(aktuelles_datum, pattern, quellpfad):
    files = []
    for file in quellpfad.glob(pattern + "*"):
        modification_date = datetime.date.fromtimestamp(file.stat().st_mtime)
        if modification_date == aktuelles_datum:
            files.append(file)
    return files

def archiviere_dateiliste(files, archivpfaddatei):
    with ZipFile(archivpfaddatei, 'w') as ergebnis_zip_datei:
        for file in files:
            ergebnis_zip_datei.write(file)
    return len(files)

def main():
    aktuelles_datum = datetime.datetime.strptime(AKTUELLES_DATUM, '%Y%m%d').date()
    files = erstelle_dateiliste(aktuelles_datum, MUSTER, QUELLPFAD)
    anzahl = archiviere_dateiliste(files, ARCHIVPFAD)
    print(f'{anzahl} Datei(en) archiviert')

if __name__ == "__main__":
    main()
tomrause
User
Beiträge: 12
Registriert: Freitag 26. Februar 2021, 19:20

Hallo Sirius3,
danke du hast mir da sehr geholfen. Bis auf eine kleine Sache habe ich das auch vollständig übernehmen können.
Bei

Code: Alles auswählen

ARCHIVPFAD = Path('K:/zielverzeichnis') / AKTUELLES_DATUM / MUSTER + '.zip'
wurde das '+' als Fehler angemerkt, ich behandele den den Namen der Archivdate in einer separaten Variable, die an ARCHIVPFAD angehängt wird.
Sirius3 hat geschrieben: Samstag 8. Mai 2021, 18:17 Benutze keine Abkürzung. Statt akt_dat heißt es aktuelles_datum.
Ja, du hast recht, ist besser mit sinnvollen Namen zu arbeiten
Sirius3 hat geschrieben: Samstag 8. Mai 2021, 18:17 Was soll das meine bei meineliste? Gibt es auch eureliste? Besser wäre dateinamen, dann weiß man auch gleich, was denn in der Liste drin ist.
s.o. In einer Vorläuferversion hieß das auch dateiliste....
Sirius3 hat geschrieben: Samstag 8. Mai 2021, 18:17 Warum chr(92)? Da muss doch jeder rätseln.
Maskierung des '\' was ja bei dem Vorgehen mit pathlib anscheinend nicht mehr gebraucht wird. Ich arbeite viel mit VBA und habe mir über die Jahre angewöhnt '\' oder ähnliche Steuerzeichen generell zu maskieren.
Sirius3 hat geschrieben: Samstag 8. Mai 2021, 18:17 Pfade stückelt man auch nicht mit + zusammen. Pfade sind keine Strings. Benutze pathlib.Path. Damit wird das Durchsuchen des Verzeichnisses auch viel einfacher.
Mit pathlib scheint das auch deutlich schneller zu laufen....
Das ist definitv etwas, was ich mir anschauen muss. Ich komme immer noch mit den Varianten der Notationen \ vs / bzw. ' vs " bei Strings vorangestelltes r oder nicht durcheinander..., danke für den Hinweis.

Sirius3 hat geschrieben: Samstag 8. Mai 2021, 18:17 Die Fehlermeldung ist eigentlich eindeutig, zumal du schon eine for-Schleife hast, das f aber gar nicht benutzt.
Das letzte verstehe ich nicht. Das "for f in liste" soll jeden Eintrag aus liste zum zipfile hinzufügen. Daher ja auch meine Nachfrage, ob ich nicht besser eien Dictionary nehmen sollte. Würdest du mir bitte hierzu noch eine Antwort geben können?
Sirius3 hat geschrieben: Samstag 8. Mai 2021, 18:17 close sollte man aufrufen oder besser gleich ganz weglassen, da du ja with hast.
Dann lass ich es auch besser weg, ist eine Fehlerquelle weniger...
Ich bitte um Hinweise
Danke
Tom
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Da habe ich die Klammern vergessen:

Code: Alles auswählen

ARCHIVPFAD = Path('K:/zielverzeichnis') / AKTUELLES_DATUM / (MUSTER + '.zip')
Alternativ mit Formatstrings:

Code: Alles auswählen

ARCHIVPFAD = Path('K:/zielverzeichnis') / AKTUELLES_DATUM / f"{MUSTER}.zip"
Deine Frage hatte ich schon beantwortet. ergebnis_zip_datei.write erwartet einen Dateinamen und keine Liste. Du hast fast alles richtig gemacht, mit der for-Schleife, nur das Argument war das falsche.
Antworten