Wie überwache ich eine Datei auf Änderungen?

Lesezeit: 10 Minuten

Benutzer-Avatar
Jon Käfig

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.

    – 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

Benutzer-Avatar
simao

Haben Sie versucht, zu verwenden Wachhund?

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

Benutzer-Avatar
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

Benutzer-Avatar
hipersayan_x

Wenn Sie eine Multiplattform-Lösung wünschen, dann prüfen Sie QFileSystemWatcher. Hier ein Beispielcode (nicht bereinigt):

from PyQt4 import QtCore

@QtCore.pyqtSlot(str)
def directory_changed(path):
    print('Directory Changed!!!')

@QtCore.pyqtSlot(str)
def file_changed(path):
    print('File Changed!!!')

fs_watcher = QtCore.QFileSystemWatcher(['/path/to/files_1', '/path/to/files_2', '/path/to/files_3'])

fs_watcher.connect(fs_watcher, QtCore.SIGNAL('directoryChanged(QString)'), directory_changed)
fs_watcher.connect(fs_watcher, QtCore.SIGNAL('fileChanged(QString)'), file_changed)

  • 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)

Benutzer-Avatar
Michael Palmer

Kasse pynotifizieren.

inotify ersetzt dnotify (aus einer früheren Antwort) in neueren Linux-Versionen und ermöglicht die Überwachung auf Dateiebene statt auf Verzeichnisebene.

  • Um diese Antwort nicht zu dämpfen, aber nachdem ich diesen Artikel gelesen habe, würde ich sagen, dass es vielleicht keine so glamouröse Lösung ist wie gedacht. serpentine.com/blog/2008/01/04/why-you-should-not-use-pyinotify

    – NuclearPeon

    22. November 2014 um 4:53 Uhr

  • 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!

  • Um diese Antwort nicht zu dämpfen, aber nachdem ich diesen Artikel gelesen habe, würde ich sagen, dass es vielleicht keine so glamouröse Lösung ist wie gedacht. serpentine.com/blog/2008/01/04/why-you-should-not-use-pyinotify

    – NuclearPeon

    22. November 2014 um 4:53 Uhr

  • 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

1099090cookie-checkWie überwache ich eine Datei auf Änderungen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy