419 Stimmen

Wie kann ich eine Datei auf Änderungen überwachen?

Ich habe eine Protokolldatei, die von einem anderen Prozess geschrieben wird und die ich auf Änderungen überwachen möchte. Jedes Mal, wenn eine Änderung auftritt, möchte ich die neuen Daten einlesen, um sie zu verarbeiten.

Wie kann man das am besten machen? Ich hatte gehofft, es gäbe eine Art von Haken von der PyWin32-Bibliothek. Ich habe die win32file.FindNextChangeNotification Funktion, weiß aber nicht, wie man sie auffordert, eine bestimmte Datei zu überwachen.

Wenn jemand so etwas schon einmal gemacht hat, wäre ich sehr dankbar zu erfahren, wie...

[Bearbeiten] Ich hätte erwähnen sollen, dass ich eine Lösung gesucht habe, die keine Abfrage erfordert.

[Bearbeiten] Verflucht! Es scheint, dass dies nicht über ein gemapptes Netzlaufwerk funktioniert. Ich vermute, dass Windows die Aktualisierungen der Datei nicht wie bei einem lokalen Laufwerk "mitbekommt".

3voto

bas080 Punkte 163

Dies ist ein Beispiel für die Überprüfung einer Datei auf Änderungen. Das ist vielleicht nicht die beste Methode, aber es ist ein kurzer Weg.

Praktisches Werkzeug zum Neustart der Anwendung, wenn Änderungen an der Quelle vorgenommen wurden. Ich habe das gemacht, als ich mit pygame gespielt habe, damit ich sehen kann, wie die Auswirkungen unmittelbar nach dem Speichern der Datei stattfinden.

Bei der Verwendung in Pygame sollte man sicherstellen, dass die Sachen in der 'while'-Schleife in der Spielschleife aka update oder was auch immer platziert werden. Andernfalls wird Ihre Anwendung in einer Endlosschleife stecken bleiben und Sie werden nicht sehen, dass Ihr Spiel aktualisiert wird.

file_size_stored = os.stat('neuron.py').st_size

  while True:
    try:
      file_size_current = os.stat('neuron.py').st_size
      if file_size_stored != file_size_current:
        restart_program()
    except: 
      pass

Für den Fall, dass Sie den Neustart-Code benötigen, den ich im Internet gefunden habe. Hier ist er. (Nicht relevant für die Frage, obwohl er sich als nützlich erweisen könnte)

def restart_program(): #restart application
    python = sys.executable
    os.execl(python, python, * sys.argv)

Viel Spaß dabei, die Elektronen dazu zu bringen, das zu tun, was du willst.

2voto

imp Punkte 1733
ACTIONS = {
  1 : "Created",
  2 : "Deleted",
  3 : "Updated",
  4 : "Renamed from something",
  5 : "Renamed to something"
}
FILE_LIST_DIRECTORY = 0x0001

class myThread (threading.Thread):
    def __init__(self, threadID, fileName, directory, origin):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.fileName = fileName
        self.daemon = True
        self.dir = directory
        self.originalFile = origin
    def run(self):
        startMonitor(self.fileName, self.dir, self.originalFile)

def startMonitor(fileMonitoring,dirPath,originalFile):
    hDir = win32file.CreateFile (
        dirPath,
        FILE_LIST_DIRECTORY,
        win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE,
        None,
        win32con.OPEN_EXISTING,
        win32con.FILE_FLAG_BACKUP_SEMANTICS,
        None
    )
    # 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_M in results:
            full_filename = os.path.join (dirPath, file_M)
            #print file, ACTIONS.get (action, "Unknown")
            if len(full_filename) == len(fileMonitoring) and action == 3:
                #copy to main file
                ...

2voto

Magnus Punkte 1983

Da ich es global installiert habe, verwende ich am liebsten nodemon. Wenn Ihr Quellcode in src und Ihr Einstiegspunkt ist src/app.py dann ist es so einfach wie:

nodemon -w 'src/**' -e py,html --exec python src/app.py

... wo -e py,html können Sie festlegen, welche Dateitypen auf Änderungen überwacht werden sollen.

1voto

Hier ist ein Beispiel, das auf die Überwachung von Eingabedateien ausgerichtet ist, die nicht mehr als eine Zeile pro Sekunde schreiben, aber normalerweise viel weniger. Das Ziel ist es, die letzte Zeile (die zuletzt geschriebene) an die angegebene Ausgabedatei anzuhängen. Ich habe dies von einem meiner Projekte kopiert und einfach alle irrelevanten Zeilen gelöscht. Sie müssen die fehlenden Symbole ausfüllen oder ändern.

from PyQt5.QtCore import QFileSystemWatcher, QSettings, QThread
from ui_main_window import Ui_MainWindow   # Qt Creator gen'd 

class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        Ui_MainWindow.__init__(self)
        self._fileWatcher = QFileSystemWatcher()
        self._fileWatcher.fileChanged.connect(self.fileChanged)

    def fileChanged(self, filepath):
        QThread.msleep(300)    # Reqd on some machines, give chance for write to complete
        # ^^ About to test this, may need more sophisticated solution
        with open(filepath) as file:
            lastLine = list(file)[-1]
        destPath = self._filemap[filepath]['dest file']
        with open(destPath, 'a') as out_file:               # a= append
            out_file.writelines([lastLine])

Natürlich ist die umfassende Klasse QMainWindow nicht unbedingt erforderlich, d.h. Sie können QFileSystemWatcher allein verwenden.

0voto

Rafael Beirigo Punkte 1036
import inotify.adapters
from datetime import datetime

LOG_FILE='/var/log/mysql/server_audit.log'

def main():
    start_time = datetime.now()
    while True:
        i = inotify.adapters.Inotify()
        i.add_watch(LOG_FILE)
        for event in i.event_gen(yield_nones=False):
            break
        del i

        with open(LOG_FILE, 'r') as f:
            for line in f:
                entry = line.split(',')
                entry_time = datetime.strptime(entry[0],
                                               '%Y%m%d %H:%M:%S')
                if entry_time > start_time:
                    start_time = entry_time
                    print(entry)

if __name__ == '__main__':
    main()

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X