Ich habe eine Protokolldatei, die von einem anderen Prozess geschrieben wird, den ich auf Änderungen überwachen möchte. Jedes Mal, wenn eine Änderung auftritt, möchte ich die neuen Daten einlesen, um sie zu verarbeiten.
Was ist der beste Weg, dies zu tun? Ich hatte gehofft, dass es eine Art Haken aus der PyWin32-Bibliothek geben würde. Ich habe die gefunden win32file.FindNextChangeNotification funktionieren, aber keine Ahnung haben, wie man es auffordert, eine bestimmte Datei anzusehen.
Wenn jemand so etwas gemacht hat, wäre ich wirklich dankbar zu hören, wie …
[Edit] Ich hätte erwähnen sollen, dass ich nach einer Lösung suchte, die keine Abfrage erfordert.
[Edit] Flüche! Es scheint, dass dies nicht über ein zugeordnetes Netzlaufwerk funktioniert. Ich vermute, dass Windows keine Aktualisierungen der Datei so “hört”, wie es auf einer lokalen Festplatte der Fall ist.
unter Linux könnte man verwenden strace Überwachung write fordert dazu auf
– test30
30. März 2016 um 9:28 Uhr
Die Antwort von @simao verwendet python-watchdog. Python-Watchdog hat eine großartige Dokumentation –> hier ist ein Link zur [“QuickStart”] Dokumentation, die ein minimales Codebeispiel bereitstellt, das das aktuelle Arbeitsverzeichnis überwacht.
Python-API-Bibliothek und Shell-Dienstprogramme zur Überwachung von Dateisystemereignissen.
Verzeichnisüberwachung leicht gemacht mit
Eine plattformübergreifende API.
Ein Shell-Tool zum Ausführen von Befehlen als Reaktion auf Verzeichnisänderungen.
Beginnen Sie schnell mit einem einfachen Beispiel in Schnellstart…
Installierbar mit easy_install? Prüfen. Freie Lizenz? Prüfen. Löst das Problem auf den großen Plattformen? Prüfen. Ich unterstütze diese Antwort. Einziger Hinweis: die Beispiel auf ihrer Projektseite funktioniert out of the box nicht. Verwenden die auf ihrem github stattdessen.
– Inaimathi
22. Oktober 2012 um 20:25 Uhr
Wir verwenden Watchdog. Wir können zu QFileSystemWatcher wechseln. Nur eine faire Warnung – Watchdog ist gut, aber weit davon entfernt, auf allen Plattformen (zu diesem Zeitpunkt) perfekt zu sein. Jedes Betriebssystem hat seine Eigenheiten. Also, wenn Sie nicht darauf bedacht sind, es perfekt zu machen, werden Sie sich die Haare ausreißen. Wenn Sie nur etwa 10 Dateien ansehen möchten, würde ich eine Umfrage durchführen. Das Zwischenspeichern von Betriebssystemfestplatten ist sehr ausgereift, und Watchdog umfasst sowieso das Abfragen von APIs. Es dient IMHO hauptsächlich zum Ansehen riesiger Ordnerstrukturen.
– SilentSteel
15. Oktober 2013 um 23:29 Uhr
Mein einziger Kritikpunkt bei Watchdog ist, dass es viele Abhängigkeiten gibt. Natürlich weniger als PyQt, aber es funktioniert nicht und fühlt sich nicht an wie die minimale Best-Practice-Lösung, die einen Job erledigt und alles richtig macht.
– AndreasT
15. Januar 2014 um 12:36 Uhr
Ist @denfromufa hier richtig? Sperrt Watchdog wirklich Dateien, sodass sie nicht gleichzeitig bearbeitet werden können, während Watchdog sie beobachtet? Ich kann das kaum glauben, es wäre völlig nutzlos.
– Michael Müller
9. Dezember 2015 um 23:24 Uhr
@MichelMüller Ich habe gerade dieses Beispiel überprüft (siehe Link unten) und es funktioniert! Ich bin mir nicht sicher, was vorher falsch war, aber diese Antwort enthält kein Beispiel. stackoverflow.com/a/18599427/2230844
– denfromufa
10. Dezember 2015 um 0:24 Uhr
Deestan
Wenn die Abfrage für Sie gut genug ist, würde ich einfach beobachten, ob sich der Dateistatus “Geänderte Zeit” ändert. Um es zu lesen:
os.stat(filename).st_mtime
(Beachten Sie auch, dass die Windows-native Änderungsereignislösung nicht unter allen Umständen funktioniert, z. B. auf Netzlaufwerken.)
import os
class Monkey(object):
def __init__(self):
self._cached_stamp = 0
self.filename="/path/to/file"
def ook(self):
stamp = os.stat(self.filename).st_mtime
if stamp != self._cached_stamp:
self._cached_stamp = stamp
# File has changed, so do something...
Wie kann man das in einem Intervall machen?
– Dopatraman
4. Mai 2016 um 15:16 Uhr
@dopatraman So können Sie dies in einem Intervall tun: ` import sys import time pub = Monkey() while True: try: time.sleep(1) pub.watch() außer KeyboardInterrupt: print(‘\nDone’) break except : print(f’Unbehandelter Fehler: {sys.exc_info()[0]}’) `
– Vlad Bezden
25. April 2017 um 19:22 Uhr
Tolle einfache Lösung! Ich habe ein Häkchen hinzugefügt, um zu verhindern, dass die Datei bei der ersten Ausführung geändert wird: if self._cached_stamp is not None.
– Noumenon
27. Februar 2020 um 16:28 Uhr
da ist kein watch Methode, wie @VladBezden schrieb. fehlt Code?
– Lei Yang
22. Januar 2021 um 8:15 Uhr
hipersayan_x
Wenn Sie eine Multiplattform-Lösung wünschen, dann prüfen Sie QFileSystemWatcher. Hier ein Beispielcode (nicht bereinigt):
Ich denke, dass dies wahrscheinlich die beste Antwort der Gruppe ist, da sie sich entweder a) auf das FileSystemwatcher-Objekt von Win32 verlassen und nicht portiert werden können oder b) die Datei abfragen (was schlecht für die Leistung ist und nicht skaliert). Schade, dass Python diese Funktion nicht eingebaut hat, da PyQt eine große Abhängigkeit darstellt, wenn Sie nur die Klasse QFileSystemWatcher verwenden.
– CadentOrange
13. Oktober 2011 um 10:07 Uhr
Ich mag diese Lösung. Ich wollte darauf hinweisen, dass Sie eine QApplication-Instanz benötigen, damit es funktioniert. Ich habe „app = QtGui.QApplication(sys.argv)“ direkt unter den Importen und dann „app.exec_()“ nach den Signalverbindungen hinzugefügt.
– spencewah
2. Mai 2012 um 22:36 Uhr
Ich teste dies gerade auf einer Linux-Box und sehe, dass die Methode directory_changed aufgerufen wird, aber nicht file_changed.
– Ken Kinder
22. November 2012 um 19:08 Uhr
warum nicht verwenden PySide dafür statt PyQt für so einen kleinen einsatz.
– Ciasto piekarz
16. September 2015 um 15:22 Uhr
Dies wird auf PyQt5 nicht mehr unterstützt
– Romaine Vincent
11. Februar 2020 um 14:08 Uhr
Es sollte nicht unter Windows funktionieren (vielleicht mit Cygwin?), aber für Unix-Benutzer sollten Sie den Systemaufruf “fcntl” verwenden. Hier ist ein Beispiel in Python. Es ist meistens der gleiche Code, wenn Sie ihn in C schreiben müssen (gleiche Funktionsnamen)
import time
import fcntl
import os
import signal
FNAME = "/HOME/TOTO/FILETOWATCH"
def handler(signum, frame):
print "File %s modified" % (FNAME,)
signal.signal(signal.SIGIO, handler)
fd = os.open(FNAME, os.O_RDONLY)
fcntl.fcntl(fd, fcntl.F_SETSIG, 0)
fcntl.fcntl(fd, fcntl.F_NOTIFY,
fcntl.DN_MODIFY | fcntl.DN_CREATE | fcntl.DN_MULTISHOT)
while True:
time.sleep(10000)
inotify ersetzt dnotify (aus einer früheren Antwort) in neueren Linux-Versionen und ermöglicht die Überwachung auf Dateiebene statt auf Verzeichnisebene.
pyinotify hat viele Nachteile, angefangen von einer sehr unpythonischen Codebasis bis hin zum Speicherverbrauch. Besser nach anderen Möglichkeiten suchen..
– Nachteule19
22. August 2018 um 9:31 Uhr
Nun, nachdem ich Tim Goldens Skript ein wenig gehackt habe, habe ich Folgendes, was ziemlich gut zu funktionieren scheint:
import os
import win32file
import win32con
path_to_watch = "." # look at the current directory
file_to_watch = "test.txt" # look for changes to a file called test.txt
def ProcessNewData( newData ):
print "Text added: %s"%newData
# Set up the bits we'll need for output
ACTIONS = {
1 : "Created",
2 : "Deleted",
3 : "Updated",
4 : "Renamed from something",
5 : "Renamed to something"
}
FILE_LIST_DIRECTORY = 0x0001
hDir = win32file.CreateFile (
path_to_watch,
FILE_LIST_DIRECTORY,
win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE,
None,
win32con.OPEN_EXISTING,
win32con.FILE_FLAG_BACKUP_SEMANTICS,
None
)
# Open the file we're interested in
a = open(file_to_watch, "r")
# Throw away any exising log data
a.read()
# Wait for new data and call ProcessNewData for each new chunk that's written
while 1:
# Wait for a change to occur
results = win32file.ReadDirectoryChangesW (
hDir,
1024,
False,
win32con.FILE_NOTIFY_CHANGE_LAST_WRITE,
None,
None
)
# For each change, check to see if it's updating the file we're interested in
for action, file in results:
full_filename = os.path.join (path_to_watch, file)
#print file, ACTIONS.get (action, "Unknown")
if file == file_to_watch:
newText = a.read()
if newText != "":
ProcessNewData( newText )
Es könnte wahrscheinlich eine Menge mehr Fehlerprüfung vertragen, aber um einfach eine Protokolldatei zu beobachten und etwas zu verarbeiten, bevor sie auf den Bildschirm gespuckt wird, funktioniert dies gut.
Vielen Dank an alle für Ihren Beitrag – tolle Sache!
pyinotify hat viele Nachteile, angefangen von einer sehr unpythonischen Codebasis bis hin zum Speicherverbrauch. Besser nach anderen Möglichkeiten suchen..
– Nachteule19
22. August 2018 um 9:31 Uhr
Zum Ansehen einer einzelnen Datei mit Abfrage und minimalen Abhängigkeiten finden Sie hier ein vollständig ausgearbeitetes Beispiel, das auf der Antwort von Deestan (oben) basiert:
import os
import sys
import time
class Watcher(object):
running = True
refresh_delay_secs = 1
# Constructor
def __init__(self, watch_file, call_func_on_change=None, *args, **kwargs):
self._cached_stamp = 0
self.filename = watch_file
self.call_func_on_change = call_func_on_change
self.args = args
self.kwargs = kwargs
# Look for changes
def look(self):
stamp = os.stat(self.filename).st_mtime
if stamp != self._cached_stamp:
self._cached_stamp = stamp
# File has changed, so do something...
print('File changed')
if self.call_func_on_change is not None:
self.call_func_on_change(*self.args, **self.kwargs)
# Keep watching in a loop
def watch(self):
while self.running:
try:
# Look for changes
time.sleep(self.refresh_delay_secs)
self.look()
except KeyboardInterrupt:
print('\nDone')
break
except FileNotFoundError:
# Action on file not found
pass
except:
print('Unhandled error: %s' % sys.exc_info()[0])
# Call this function each time a change happens
def custom_action(text):
print(text)
watch_file="my_file.txt"
# watcher = Watcher(watch_file) # simple
watcher = Watcher(watch_file, custom_action, text="yes, changed") # also call custom action function
watcher.watch() # start the watch going
Du könntest machen watch_file und _cached_stamp in Listen und iteriere sie in einer for-Schleife. Skaliert jedoch nicht wirklich gut für eine große Anzahl von Dateien
– 4Oh4
5. März 2018 um 15:56 Uhr
Löst dies die Aktion nicht jedes Mal aus, wenn es ausgeführt wird? _cached_stamp wird auf 0 gesetzt und dann mit os.stat(self.filename).st_mtime verglichen. _cached_stamp sollte im Konstruktor auf os.stat(self.filename).st_mtime gesetzt werden, oder?
– Seanonym
16. August 2019 um 22:08 Uhr
call_func_on_change() wird beim ersten Lauf von ausgelöst look()aber dann _cached_stamp wird aktualisiert, wird also nicht erneut ausgelöst, bis der Wert von os.stat(self.filename).st_mtime. _cached_stamp Änderungen.
– 4Oh4
18. August 2019 um 13:20 Uhr
Sie können den Wert von festlegen _cached_stamp im Konstruktor, wenn Sie nicht wollten call_func_on_change() beim ersten Lauf aufgerufen werden
– 4Oh4
18. August 2019 um 13:21 Uhr
Ich habe Ihr Skript verwendet, um eine Funktion bei Dateiänderungen aufzurufen. Meine Funktion akzeptiert keine Argumente im Gegensatz zu Ihren. Ich dachte, dass ich *args, **kwargs entfernen muss, damit es funktioniert. Es sah so aus (ich habe nur Zeilen mit Änderungen eingefügt): self.call_func_on_change(self) def custom_action(): watcher = Watcher(watch_file, custom_action()) Aber das hat nicht funktioniert. Aktion wurde nur während der ersten Iteration aufgerufen: Datei geändert ja, geändert Datei geändert Datei geändert Datei geändert Es fing an zu funktionieren, als ich *args behielt und es aufrief: watcher = Watcher(watch_file, custom_action) Ich frage mich, warum?
– zwornik
1. April 2020 um 14:10 Uhr
10990900cookie-checkWie überwache ich eine Datei auf Änderungen?yes
unter Linux könnte man verwenden
strace
Überwachungwrite
fordert dazu auf– test30
30. März 2016 um 9:28 Uhr
Die Antwort von @simao verwendet python-watchdog. Python-Watchdog hat eine großartige Dokumentation –> hier ist ein Link zur [“QuickStart”] Dokumentation, die ein minimales Codebeispiel bereitstellt, das das aktuelle Arbeitsverzeichnis überwacht.
– Trevor Boyd Smith
1. Mai 2017 um 14:36 Uhr
Sehen Tim Goldens Python Stuff: Beobachten Sie ein Verzeichnis auf Änderungen für ein Beispiel für die Verwendung der
win32file.FindNextChangeNotification
Funktion.– Martinau
5. April um 16:54 Uhr