Ordnerstrukturen auf Aktualisierung prüfen
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.
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.
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.
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.
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:
erhalte ich dauerhaft die Meldung, dass die Datei aktualisiert wurde.
Ich habe das ganze versucht in deinen Code miteinzubauen:
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
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.
Code: Alles auswählen
for filename in previous_text_files and text_files:
Code: Alles auswählen
os.stat(filename).st_atime
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")
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)
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
Sie tun eben nicht das selbe. Im einen Fall hast Du einen Zähler, im anderen nicht.
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??Karlirex hat geschrieben: ↑Mittwoch 31. März 2021, 08:12Code: Alles auswählen
for filename in previous_text_files and text_files:
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:
Code: Alles auswählen
kept_text_files = previous_text_files & text_files
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")
}
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).
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).
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:
Mein gesamtes Skript sieht nun so aus:
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()))
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)
`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.
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)
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
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
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.
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.
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+).
Um es zu beschleunigen habe ich dann multiprocessing versucht:
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
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("*")
}
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()
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
- __blackjack__
- User
- Beiträge: 13116
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@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.
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.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
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.__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.
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
- __blackjack__
- User
- Beiträge: 13116
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@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.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Alles klar.__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.
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()
- __blackjack__
- User
- Beiträge: 13116
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
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.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
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.
Soweit mein Verständnis, bin kein Dateisystem-Experte.
Mit chunksize=1 und lediglich einem (den größten Ordner) lande ich bei 418s statt 390s__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.
Den Vorschlag mit scandir, versuche ich mal anzugehen.
- __blackjack__
- User
- Beiträge: 13116
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@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.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Naja allein der größte Ordner dauert mit Pool und auch den anderen Ideen besagt 400s.__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.
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)
Mit einem drittel der Zeit kann ich mich nämlcih zu frieden stellen.