Seite 1 von 3
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Dienstag 30. März 2021, 17:13
von Karlirex
den os.stat-Fehler hatte ich, nachdem ich in meiner Logik das set mit dem stat (Path().stat().st_ctime) als Vorschlag von ElektroBerry kombinieren wollte.
Denn wenn sich die Zeit einer Datei ändert und diese mit dem ersten erstellten set verglichen wird, müsste dort ja die Änderung eintreten (diie Datei wurde aktualisiert?).
Das sich die Änderungen immer ändern liegt ja daran, dass ich das ganze nach und nach aufbaue und immer wieder teste, siehe die Meldung, dass eine Datei gelöscht wurde.
Nun ist die Frage, wenn eine aktuellere Dateio mit selben Namen kommt.
Das ich das ganze in einer while True-Schleife gebaut habe, kam ja nach dem Vorschlag von ElektroBerry. Ob ich den Durchlauf zähle oder nicht, dient hier nur zum erkennen, ob die Schleife wirklich läuft.
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Mittwoch 31. März 2021, 07:20
von Sirius3
Du hast ja schon einen stat-Aufruf von Path. Da macht es natürlich keinen Sinn, damit auch noch os.stat aufzurufen.
Und wie schon geschrieben, wenn man eine endlos-Schleife braucht nimmt man eine while-Schleife, wenn man aber einen Zähler braucht, ist halt eine for-Schleife besser.
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Mittwoch 31. März 2021, 08:12
von Karlirex
Okay, dann ist dies quasi Gesetz mit der while und for-Schleife, obwohl sie für den endlos Fall gleiches tun, danke.
Den stat-Aufruf habe ich ja bei dem set getestet, ohne Erfolg.
Beispeilsweise wäre ja hier nach dann der Fall, was passieren soll, wenn etwas "aktualisiert" wurde.
demnach würde ich hier hinter eine if-Bedingung mit einer Zeitabfrage der Datei einbauen müssen, weshalb ich wieder mit os.stat für die Datei arbeiten müsste, iwie sowas:
Das funktioniert so aber nicht, da ich keine weitere Abfrage einbaue, erweitere ich die Abfrage zu:
Code: Alles auswählen
if os.stat(filename in previous_text_files).st_atime != os.stat(filename in text_files).st_atime:
print(f"{filename} aktualisiert")
erhalte ich dauerhaft die Meldung, dass die Datei aktualisiert wurde.
Ich habe das ganze versucht in deinen Code miteinzubauen:
Code: Alles auswählen
from pathlib import Path
from time import sleep
from itertools import count
FOLDER = Path('S:\Palkovits\intern\HPLC-Daten\Jens Heller')
print("Erster Scan")
previous_text_files = set(FOLDER.rglob("*.txt"))
for i in count(1):
print(os.stat(filename).st_atime)
text_files = set(FOLDER.rglob("*.txt"))
for filename in text_files - previous_text_files:
print(f"{filename} ist neu")
for filename in previous_text_files - text_files:
print(f"{filename} gelöscht")
for filename in previous_text_files and text_files:
if os.stat(filename in previous_text_files).st_atime != os.stat(filename in text_files).st_atime:
print(f"{filename} aktualisiert")
previous_text_files = text_files
print("Lauf", i)
sleep(5)
Wo liegt denn mein Denkfehler? oder kenne ich erfahrungsmäßig gewisse Methoden nicht?
Muss ich vllt nach der Abfrage bei gleichen Sets die Datei öffnen und Zeile für Zeile vergleichen lassen?
Falls ja, wie baue ich diese Variante für n Dateien um, was ich bei Goggle fand, war nur zu konkreten Dateien.
Danke für deine Hilfe
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Mittwoch 31. März 2021, 09:18
von Sirius3
Karlirex hat geschrieben: Mittwoch 31. März 2021, 08:12
Okay, dann ist dies quasi Gesetz mit der while und for-Schleife, obwohl sie für den endlos Fall gleiches tun, danke.
Sie tun eben nicht das selbe. Im einen Fall hast Du einen Zähler, im anderen nicht.
Karlirex hat geschrieben: Mittwoch 31. März 2021, 08:12
Du kannst nicht Syntax raten und hoffen, dass es schon das macht, was Du hoffst. Hast Du Dir schonmal angeschaut, was der Ausdruck `previous_text_files and text_files` macht??
Genauso `filename in previous_text_files`! Was erwartest Du denn, was dieser Ausdruck innerhalb von os.stat macht? Und hast Du geprüft, was er wirklich macht?
Code baut man Stück für Stück auf, und testet jeden Schritt.
Also Dateien, die früher schon da waren und jetzt immer noch da sind, bekommt man über die Sets:
Jetzt hast Du ein Set mit Dateinamen. Aber wie sollst Du daraus die Änderungszeit bestimmen?
Gar nicht. Deshalb mußt Du die Zeiten schon vorher bestimmen. Also neben dem Dateinamen auch die Änderungszeit speichern. Dazu bietet sich ein Wörterbuch an.
Code: Alles auswählen
def get_files_with_atime(folder):
return {
filename: filename.stat().st_atime
for filename in folder.rglob("*.txt")
}
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Mittwoch 31. März 2021, 09:31
von Karlirex
Aber den Fall "kept_text_files", welchen du beschreibst, löst du doch genauso über das & (and), wie ich, nur dass du dem ganzen einen neuen Namen (kept_text_files) gibst. Also warum diese Änderung?
Auch wenn while/for etwas anderes darstellen, nach der Konvention, schreibe ich doch nicht 3x Code, nur damit ich dazwischen sehe, ob er wirklich durchläuft, sondern nehme dann nur die letzten Punkte aus der while-Schleife.
Den Fall, welche du mit der Funktion beschrieben hast, gibt doch erstmal den gesamten Ordner als Zeit aus, in einem Wörterbuch gespeichert, oder?
Ich gebe mich mit der ganzen Materie etwas schwer, dass mag sein. Leider komme ich aus keiner Programmierecke und erhalte halt die ein oder andere Idee und versuche mich dann daran. Wenn ich mir verschiedene Bücher dazu ansehe, fühle ich mich leider einfach nur erschlagen, gerade, weil es für eine Lösung eben 7 Wege gibt (siehe unser Schleifenthema).
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Mittwoch 31. März 2021, 09:51
von Sirius3
Es macht einen Unterschied ob man `and` oder `&` schreibt. Und natürlich schreibst Du Code immer wieder neu und um. Auch mehr als drei mal.
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Donnerstag 29. April 2021, 09:15
von Karlirex
Ich habe mich mit dem Problem der Aktualisierung nun einige Zeit beschäftigt, versucht dictionarys, sets, list und dataframes mit einander zu vergleichen, um jeweils den Unterschied im Zeitstempel zu erkennen. Leider ohne Erfolg.
Ich bekomme an der Stelle die ganze Zeit das eine print-Ausgabe, welche erstmal nicht da stehen sollte, bis eben eine Datei mit selben Namen aber unterschiedlicher Zeit in den Ordner gefügt wird.
Ich glaube ich übersehe ein Stück an dieser Stelle.
Das Stück Code für die Abfrage nach der letzten accesstime sieht so aus:
Code: Alles auswählen
for filename in previous_text_files & text_files:
with filename.stat().st_atime as filename:
if filename not in file_time:
print("neu")
dict1 = {filename: filename.stat().st_atime}
dict2 = dict(set(dict1.items()) - set(file_time.items()))
Mein gesamtes Skript sieht nun so aus:
Code: Alles auswählen
import os
from pathlib import Path
from time import sleep
import time
FOLDER = Path(r'......')
print("Erster Scan")
previous_text_files = set(FOLDER.rglob("*.txt"))
i = 0
def get_file_time(FOLDER):
return {
filename: filename.stat().st_atime
for filename in FOLDER.rglob("*.txt")
}
file_time = get_file_time(FOLDER)
while True:
file_time = get_file_time(FOLDER)
text_files = set(FOLDER.rglob("*.txt"))
for filename in text_files - previous_text_files:
print(f"{filename} ist neu")
for filename in previous_text_files - text_files:
print(f"{filename} gelöscht")
for filename in previous_text_files & text_files:
with filename.stat().st_atime as filename:
if filename not in file_time:
print("neu")
dict1 = {filename: filename.stat().st_atime}
dict2 = dict(set(dict1.items()) - set(file_time.items()))
if not text_files:
print("Keine Daten enthalten")
previous_text_files = text_files
i = i + 1
print("Lauf", i)
sleep(5)
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Donnerstag 29. April 2021, 10:49
von Sirius3
`os` und `time` werden importiert aber nicht benutzt.
FOLDER in `get_file_time` ist keine Konstante, muß also `folder` geschrieben werden.
Du suchst alle Dateien immer zwei mal, einmal mit Änderungszeit und einmal ohne. Dabei ist zweiteres völlig unnötig.
Bei dem with-Statement bekommst Du einen Fehler, wäre gut gewesen, wenn Du den hier auch posten würdest. Was hoffst Du, bewirkt with hier?
Würde das with funktionieren, wäre in `filename` die Änderungszeit gespeichert und die wäre niemals ein Schlüssel in `file_time`. Für was soll `dict1` und `dict2` gut sein?
Und wieder hast Du eine while-Schleife, die eine for-Schleife sein könnte.
Code: Alles auswählen
from pathlib import Path
from time import sleep
FOLDER = Path(r'......')
def get_filenames_with_accesstime(folder):
return {
filename: filename.stat().st_atime
for filename in FOLDER.rglob("*.txt")
}
print("Erster Scan")
previous_text_files = get_filenames_with_accesstime(FOLDER)
for i in count(1):
print("Lauf", i)
text_files = get_filenames_with_accesstime(FOLDER)
for filename in set(text_files) - set(previous_text_files):
print(f"{filename} ist neu")
for filename in set(previous_text_files) - set(text_files):
print(f"{filename} gelöscht")
for filename in set(previous_text_files) & set(text_files):
if previous_text_files[filename] != text_files[filename]:
print(f"{filename} geändert")
if not text_files:
print("Keine Daten enthalten")
previous_text_files = text_files
sleep(5)
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Donnerstag 29. April 2021, 14:15
von Karlirex
Also das with war die Idee, damit die Zeitstempel abzufragen, da ich so schon Programme gesehen habe, die Ordner nur dann öffnen, wenn dort bpsw auch ein with Argument erfüllt ist.
Das dict war die Überlegung die Zeiten so speichern und vergleichen zukönnen.
Wenn ich deinen Code nun so übernehme, laufe ich zwar in keinerlei Fehler, dennoch läuft das Programm an der Schleife mit der Aktualisierung scheinbar vorbei. Denn ich erhalte keine Meldung, wenn ich die neue Datei mit dem geänderten Zugriff in den Ordner überschreibe.
Kannst Du mir eventuell deine if-Abfrage genauer erklären, also warum nun da das [filename] enthalten ist?
Vielleicht finde ich dann auch dort den letzten Fehler, damit das Programm passend läuft.
Vielen Dank, beste Grüße
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Donnerstag 29. April 2021, 16:07
von Sirius3
Was Wörterbücher sind, und wie man sie verwendet, gehört zu den absoluten Grundlagen.
Wann atime, mtime oder ctime geändert werden, hängt vom Filesystem ab. Wie das unter Windows gehandhabt wird, kann ich gerade nicht sagen. Aber wenn Du Dateien änderst, interessiert dich eher mtime.
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Montag 12. Dezember 2022, 09:09
von Karlirex
Hallo,
ich erwecke den Thread nochmal zum Leben
Meine Ordner sind mit der Zeit deutlich größer geworden.
Dabei habe ich längere Laufzeiten der Funktion festegestellt (aktuell 6min+).
Code: Alles auswählen
def get_filenames_with_accesstime(folder):
return {
filename: filename.stat().st_atime
for filename in FOLDER.rglob("*")
}
Um es zu beschleunigen habe ich dann multiprocessing versucht:
Code: Alles auswählen
def my_func(FOLDER, queue):
queue.put({
filename: filename.stat().st_mtime
for filename in FOLDER.rglob("*")
})
queue = multiprocessing.Queue()
previous_text_files = dict()
start = timeit.default_timer()
for i in path_list:
p1 = multiprocessing.Process(target=my_func, args=(Path(i), queue))
p1.start()
previous_text_files.update(queue.get())
p1.join()
das ist aber auch nur 0,4s schneller.
Gibts es eine andere Möglichkeit die Funktion zu erweitern, habe ich etwas falsch gemacht oder ist aufgrund der Datenmenge das hier einfach limitiert?
Danke für eure Hilfe und Grüße
Karlirex
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Montag 12. Dezember 2022, 11:12
von __blackjack__
@Karlirex: Da ist *gar kein* Gewinn zu erwarten, weil da immer nur *ein* zusätzlicher Prozess läuft, während der Hauptprozess auf den *wartet* und nichts tut. Ich würde da erst einmal schauen ob ein `Pool` und `imap_unordered()`, `map()`, oder die `*_async()`-Methoden verwendet werden kann, bevor ich mir da selbst was zur Übertragung von Daten bastele und die Funktion ändern muss, die das ganze ausführt. Selbst dann wären da noch die `*_async()`-Methoden von `Pool`.
Ich wette es wurde schon mal was zu Namen gesagt. `my_*` ist ein sinnloser Präfix, der in 99,9999% nichts aussagt und da nicht hingehört. `FOLDER` wäre eine Konstante, Argumentnamen sind aber nie Konstanten. `i` ist als Name für etwas anderes als ganze Zahlen falsch. Niemand kommt darauf, das es sich in diesem Fall um einen Ordnerpfadnamen handelt. `filename` ist falsch, weil an den Namen nicht nur Dateinamen (eigentlich ja *Pfade*), sondern auch Ordnerpfade gebunden werden. Daraus folgt, dass auch `get_filenames_with_accesstime()` als Name falsch ist.
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Montag 12. Dezember 2022, 12:09
von Karlirex
__blackjack__ hat geschrieben: Montag 12. Dezember 2022, 11:12
Ich wette es wurde schon mal was zu Namen gesagt. `my_*` ist ein sinnloser Präfix, der in 99,9999% nichts aussagt und da nicht hingehört. `FOLDER` wäre eine Konstante, Argumentnamen sind aber nie Konstanten. `i` ist als Name für etwas anderes als ganze Zahlen falsch. Niemand kommt darauf, das es sich in diesem Fall um einen Ordnerpfadnamen handelt. `filename` ist falsch, weil an den Namen nicht nur Dateinamen (eigentlich ja *Pfade*), sondern auch Ordnerpfade gebunden werden. Daraus folgt, dass auch `get_filenames_with_accesstime()` als Name falsch ist.
Zu my gabs schon Kommentare ja, zum reinen Testen bei Problemen benenne ich es aber "schnell/einfach" oder übernehme von Stackoverflow direkt um zu schauen ob sich was am Problem ändert. Tut sich das, werden die Namen angepasst.
Zur der Sache mit FOLDER, filename, get_filenames_with_accesstime() finde ich ganz interessant, da ich diese Bezeichnung von Sirius übernommen habe und ihr beide ja sehr darauf achtet, dass immer alles korrekt benannt ist, dies auch hier dann doch "falsch" ist, siehe zwei drei Postings vorher von ihm.
Grüße
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Montag 12. Dezember 2022, 13:01
von __blackjack__
@Karlirex: Zumindest `FOLDER` war korrekt, weil das dort noch eine Konstante war, als das noch so hiess. Ich mache in der Regel einen Unterschied in der Benennung das `Path`-Objekte auch wirklich `path` im Namen haben um bei `file_path` vs. `filename` zu wissen, dass das eine ein Pfad-Objekt (zu einer Datei) ist, und das andere eine Zeichenkette mit einem Dateinamen. Insbesondere in Programmen/Programmteilen wo beide Varianten vorkommen können, vermeidet das Verwirrung.
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Montag 12. Dezember 2022, 13:56
von Karlirex
__blackjack__ hat geschrieben: Montag 12. Dezember 2022, 13:01
@Karlirex: Zumindest `FOLDER` war korrekt, weil das dort noch eine Konstante war, als das noch so hiess. Ich mache in der Regel einen Unterschied in der Benennung das `Path`-Objekte auch wirklich `path` im Namen haben um bei `file_path` vs. `filename` zu wissen, dass das eine ein Pfad-Objekt (zu einer Datei) ist, und das andere eine Zeichenkette mit einem Dateinamen. Insbesondere in Programmen/Programmteilen wo beide Varianten vorkommen können, vermeidet das Verwirrung.
Alles klar.
Ich habe mal nach dem Tutorial von Pool gearbeitet und folgendes probiert:
Code: Alles auswählen
from multiprocessing import Pool
process = Pool(5)
with process:
start = timeit.default_timer()
results = process.map(get_filenames_with_accesstime, path_list)
end = timeit.default_timer()
dabei wird eine Zeitverbesserung von 8s erzielt. mit einem apply_async / map_async /mehr Workern erhalte ich keinen weiteren Zeitschub. Schade.
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Montag 12. Dezember 2022, 14:11
von __blackjack__
Ich würde hier wahrscheinlich noch die `chunksize` manuell auf 1 setzen sofern in `path_list` nicht viele Werte vorkommen die nur ganz wenige Ergebnisse liefern.
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Montag 12. Dezember 2022, 21:43
von bords0
Ich hätte noch den Vorschlag, mit os.scandir() zu arbeiten. Nach meiner Erfahrung bzw. Erinnerung ist das schneller, wenn die Filesystem-Zugriffe der Flaschenhals sind. Die DirEntry-Objekte, die man von os.scandir() bekommt, ersparen den zusätzlichen stat()-Aufruf, weil sie die Werte gleich einlesen und cachen. Man muss also nur einmal ans Filesystem ran, und auch nicht für jede Datei einzeln.
Soweit mein Verständnis, bin kein Dateisystem-Experte.
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Dienstag 13. Dezember 2022, 08:18
von Karlirex
__blackjack__ hat geschrieben: Montag 12. Dezember 2022, 14:11
Ich würde hier wahrscheinlich noch die `chunksize` manuell auf 1 setzen sofern in `path_list` nicht viele Werte vorkommen die nur ganz wenige Ergebnisse liefern.
Mit chunksize=1 und lediglich einem (den größten Ordner) lande ich bei 418s statt 390s
Den Vorschlag mit scandir, versuche ich mal anzugehen.
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Dienstag 13. Dezember 2022, 08:47
von __blackjack__
@Karlirex: Das dann nur mit *einem* Ordner zu machen ist ja ein bisschen witzlos, denn da wird dann ja garantiert nichts parallel ausgeführt, und man hat nur den zusätzlichen Overhead das die Daten zwischen den Prozessen kommuniziert werden müssen.
Re: Ordnerstrukturen auf Aktualisierung prüfen
Verfasst: Dienstag 13. Dezember 2022, 10:30
von Karlirex
__blackjack__ hat geschrieben: Dienstag 13. Dezember 2022, 08:47
@Karlirex: Das dann nur mit *einem* Ordner zu machen ist ja ein bisschen witzlos, denn da wird dann ja garantiert nichts parallel ausgeführt, und man hat nur den zusätzlichen Overhead das die Daten zwischen den Prozessen kommuniziert werden müssen.
Naja allein der größte Ordner dauert mit Pool und auch den anderen Ideen besagt 400s.
Code: Alles auswählen
start = timeit.default_timer()
#for path in path_list:
for root, dirs, files in os.walk(path_list):
for filename in files:
file_path = os.path.join(root, filename)
end = timeit.default_timer()
print("Zeit für einen Durchlauf: ", end-start)
hier die Idee mit walk, das dauert 112s für dazu noch alle anderen Ordner. Ich muss jetzt nur noch herausfinden, wie ich passend an die stats komme und das dann in ein Set so wie zuvor packen.
Mit einem drittel der Zeit kann ich mich nämlcih zu frieden stellen.