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".

21voto

Michael Palmer Punkte 201

Auschecken pyinotify .

inotify ersetzt dnotify (aus einer früheren Antwort) in neueren Linuxen und erlaubt die Überwachung auf Datei- statt auf Verzeichnisebene.

17voto

4Oh4 Punkte 1691

Um eine einzelne Datei mit Polling und minimalen Abhängigkeiten zu beobachten, finden Sie hier ein vollständig ausgearbeitetes Beispiel, das auf der Antwort von Deestan (oben):

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

14voto

Jon Cage Punkte 34808

Nun, nachdem ich das Skript von Tim Golden ein wenig bearbeitet habe, habe ich folgendes Ergebnis, das ganz 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 mit einer Ladung mehr Fehlerprüfung zu tun, aber für einfach eine Log-Datei zu beobachten und einige Verarbeitung auf sie, bevor es auf dem Bildschirm ausspuckt, funktioniert dies gut.

Vielen Dank an alle für ihre Beiträge - tolle Sachen!

9voto

ronedg Punkte 1140

Dies ist eine weitere Modifikation des Skripts von Tim Goldan, das auf Unix-Typen läuft und eine einfache Überwachung von Dateiveränderungen mit Hilfe eines Dict (file=>time) hinzufügt.

Verwendung: whateverName.py path_to_dir_to_watch

#!/usr/bin/env python

import os, sys, time

def files_to_timestamp(path):
    files = [os.path.join(path, f) for f in os.listdir(path)]
    return dict ([(f, os.path.getmtime(f)) for f in files])

if __name__ == "__main__":

    path_to_watch = sys.argv[1]
    print('Watching {}..'.format(path_to_watch))

    before = files_to_timestamp(path_to_watch)

    while 1:
        time.sleep (2)
        after = files_to_timestamp(path_to_watch)

        added = [f for f in after.keys() if not f in before.keys()]
        removed = [f for f in before.keys() if not f in after.keys()]
        modified = []

        for f in before.keys():
            if not f in removed:
                if os.path.getmtime(f) != before.get(f):
                    modified.append(f)

        if added: print('Added: {}'.format(', '.join(added)))
        if removed: print('Removed: {}'.format(', '.join(removed)))
        if modified: print('Modified: {}'.format(', '.join(modified)))

        before = after

9voto

Bruno De Fraine Punkte 42481

Siehe meine Antwort zu einer ähnliche Frage . Sie können die gleiche Schleife in Python ausprobieren. Diese Seite schlägt vor:

import time

while 1:
    where = file.tell()
    line = file.readline()
    if not line:
        time.sleep(1)
        file.seek(where)
    else:
        print line, # already has newline

Siehe auch die Frage tail() eine Datei mit Python .

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