Programm zum Datenabgleich 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
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Hallo, ich möchte mit ein kleines Programm zum "synchronisieren" von Daten in 2 Ordner schreiben.
Mir fehlt aber leider so richtig der Algorithmus zum Problem.

Also ich möchte den Inhalt von 2 Ordner (die haben auch noch Unterordner) vergleichen.
Sobald bei Ordner a etwas geändert wurde, Daten/Ordner erstellt oder Dateien geändert wurde, soll diese in Ordner b an gleicher Stelle kopiert werden.
Ordner b ist also ein backup. Das Programm soll jeden Tag 1x ausgeführt werden.

Jetzt zu meiner Denkweise:

Als erstes schauen ob ein neuer Ordner oder neue Datei hinzu gekommen ist:
Ich lese ich mit "os.walk" erstmal in beiden Ordner alle Unterordner und Dateien ein, speichere es in 2 versch. Listen, dann werden die Listen verglichen mit "zip_longest" verglichen (aber komischerweise ist dann die Reihenfolge anders, klappt also nicht).

Dann würde ich von allen Dateien das Änderungsdatum vergleichen. Anschließend die Dateien, die die letzten 24h geändert wurden in Ordner b kopieren bzw überschreiben.

Soviel zur meiner Theorie und Problem.


Welchen Algorithmus würdet ihr mir vorschlagen? Vielleicht reicht es auch nur die geänderten Ordner/Dateien der letzten 24h zu kopieren?

Gruß
Benutzeravatar
__blackjack__
User
Beiträge: 14056
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@egon11: In neuem Code würde ich `pathlib` statt `os` verwenden.

Warum den Zielordner komplett abklappern? Das wäre nur notwendig wenn dort auch Dateien gelöscht werden sollen, die im Quellordner nicht (mehr) vorhanden sind. Was in der Beschreibung zumindest bisher ja nicht vorkommt.

Reihenfolge: Die würde ich erst einmal als ungeordnet ansehen. `os.listdir()` garantiert beispielsweise keine besondere Reihenfolge. Das listet auf in der Reihenfolge wie das Betriebssystem/der Dateisystemtreiber die Dateien liefert. Das kann irgendwie sortiert sein, muss es aber nicht. Wenn man also so eine Dateiliste in einer bestimmten Reihenfolge haben wollen würde, dann muss man die auf jeden Fall selber sortieren.

`zip_longest()` kann aber auch bei garantiert sortierten Listen nicht funktionieren, denn sobald die erste Datei kommt die nur auf einer der beiden Seiten existiert, passen ja logischerweise alle folgenden Paare nicht mehr zusammen.

Der einfachste Algorithmus wäre es über die Pfade im Quellordner zu iterieren und bei jedem zu schauen, ob der auf der Zielseite existiert. Falls nicht, kopieren. Falls ja, schauen ob Quelle neuer, dann kopieren. Eventuell noch irgendwie den Fall behandeln, dass das *Ziel* neuer ist. Also das zumindest mal protokollieren.

Beim Vergleich der Zeiten kann es ein kleines Problem geben falls unterschiedliche Dateisysteme bei Quelle und Ziel verwendet werden, und sich die Auflösung in der Zeitstempel gespeichert werden, bei beiden unterscheidet. Das muss man beim Zeitvergleich dann entsprechend berücksichtigen.

Last but not least: Ich würde rsync verwenden, bevor ich mir da was selber programmiere. Das gibt es schon, das funktioniert zuverlässig, das kann mehr, und das ist im Zweifelsfall auch effizienter.

Falls irgendwann einmal in beide Richtungen abgeglichen werden soll, lohnt sich ein Blick auf Unison.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ich habe gerade mal nach pathlib geschaut, aber wie kann ich da ALLE Unterordner erwischen?
bei `iterdir`wird nur der nächstgelegene Unterordner angezeigt, oder muss man so langer iterieren bis kein Ordner mehr da ist?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich kann nur nochmal mit Nachdruck __blackjacks__ Hinweis zu rsync wiederholen. Benutzt das einfach. So ein Programm ist alles andere als trivial, und bei dir hakt es ja schon am grundlegenden.

Zur konkreten Frage: ja, man muss iterieren. Aber iterdir liefert auch einfach nur alle Kinder dieses Verzeichnisses. Weder sind die gefiltert nach Verzeichnissen oder Datei, noch steigt das tiefer ab. Ich wuerde wahrscheinlich eher rglob mit einem catchall-Pattern benutzen:

Code: Alles auswählen

tmp = pathlib.Path("/tmp")
list(tmp.rglob("**/*"))
Ordnung musst du dann aber noch selbst herstellen.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ok vielen dank.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

Anbei habe ich noch eine Frage, warum nimmt man jetzt statt `os.path` `pathlib`?
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Weil pathlib die schönere und modernere Schnittstelle ist. So werden Pfaden als Objekte behandelt, die entsprechende Methoden haben, statt Funktionen Zeichenketten zu übergeben, die ein Pfad sein könnten.
egon11
User
Beiträge: 363
Registriert: Mittwoch 14. Dezember 2016, 20:59

OK danke.
Benutzeravatar
kbr
User
Beiträge: 1508
Registriert: Mittwoch 15. Oktober 2008, 09:27

Du kannst os.path auch weiterhin verwenden. Die Bibliothek ist etwas älter und etwas mehr „low level“. Das heißt, Du musst oftmals mehr Code schreiben und hast mehr Möglichkeiten Fehler zu machen.
Sirius3
User
Beiträge: 18274
Registriert: Sonntag 21. Oktober 2012, 17:20

@__deets__: das ** ist in `rglob` schon enthalten.
Also entweder:

Code: Alles auswählen

tmp = pathlib.Path("/tmp")
list(tmp.rglob("*"))
oder

Code: Alles auswählen

tmp = pathlib.Path("/tmp")
list(tmp.glob("**/*"))
Antworten