Frage

Ich habe eine Log-Datei von einem anderen Prozess geschrieben, die ich für Änderungen sehen will. Jedes Mal, wenn eine Änderung auftritt Ich möchte die neuen Daten in lesen, einige Verarbeitung auf, es zu tun.

Was ist der beste Weg, dies zu tun? Ich hatte gehofft, es würde eine Art Haken aus der PyWin32 Bibliothek sein. Ich habe die win32file.FindNextChangeNotification Funktion gefunden, haben aber keine Ahnung, wie es zu fragen, eine bestimmte Datei zu sehen.

Wenn jemand etwas Derartiges getan würde ich wirklich dankbar sein, zu hören, wie ...

[Bearbeiten] ich erwähnt habe, soll, dass ich nach einer Lösung, die nicht Polling erfordert.

[Bearbeiten] Flüche! Es scheint dies nicht ein zugeordnetes Netzlaufwerk funktioniert über. Ich schätze, dass Fenster nicht ‚hören‘ alle Aktualisierungen der Datei so, wie es auf einer lokalen Festplatte der Fall ist.

War es hilfreich?

Lösung

Haben Sie schon bei der Dokumentation sehen auf http://timgolden.me.uk /python/win32_how_do_i/watch_directory_for_changes.html ? Wenn Sie nur es brauchen scheint das zweite Beispiel unter Windows zu arbeiten, genau das zu sein, was Sie wollen (wenn Sie den Pfad des Verzeichnisses mit dem von der Datei, die Sie sehen wollen, tauschen).

Ansonsten Polling wird wahrscheinlich die einzigen wirklich plattformunabhängige Option sein.

. Hinweis: Ich habe eine dieser Lösungen nicht versucht

Andere Tipps

Haben Sie versucht Watchdog mit?

  

Python-API-Bibliothek und Shell-Utilities Dateisystemereignisse zu überwachen.

     

Verzeichnisüberwachung leicht gemacht mit

     
      
  • Ein Cross-Plattform-API.
  •   
  • Ein Shell-Tool Befehle in Reaktion auf Verzeichnisänderungen auszuführen.
  •   
     

schnell mit einem einfachen Beispiel Erste Schritte in Kurz ...

Wenn Polling gut genug für Sie ist, würde ich nur zuschauen, wenn die „modifizierte Zeit“ Änderungen Datei stat. Um es zu lesen:

os.stat(filename).st_mtime

(Beachten Sie auch, dass die native Windows-Änderungsereignis Lösung nicht unter allen Umständen funktioniert, beispielsweise auf Netzlaufwerke).

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

Wenn Sie eine Multi-Plattform-Lösung wollen, dann überprüfen Sie QFileSystemWatcher . Hier ist ein Beispiel-Code (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)

Es soll nicht auf Windows arbeiten (vielleicht mit Cygwin?), Aber für Unix-Benutzer, sollten Sie den „Fcntl“ Systemaufruf verwenden. Hier ist ein Beispiel in Python. Es ist meist der gleiche Code, wenn Sie es in C (gleiche Funktionsnamen)

schreiben müssen
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)

Schauen Sie sich pyinotify .

inotify ersetzt dnotify (aus einer früheren Antwort) in neueren Linux-Versionen und erlaubt Dateiebene anstatt auf Verzeichnisebene Überwachung.

Nun, nachdem ein bisschen Hacking von Tim Golden Drehbuch, ich habe die folgende, die 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 Last mehr Fehlerprüfung, aber für nur eine Protokolldatei zu beobachten und einige Verarbeitung auf, es zu tun, bevor es aus auf den Bildschirm zu spucken, das funktioniert gut.

Vielen Dank allen für Ihre Eingabe - great stuff

Einfachste Lösung für mich ist mit dem Werkzeug watchmedo des Watchdog

https://pypi.python.org/pypi/watchdog Ich habe jetzt ein Prozess, der die sQL-Dateien in einem Verzeichnis sucht und führt sie aus, falls erforderlich.

watchmedo shell-command \
--patterns="*.sql" \
--recursive \
--command='~/Desktop/load_files_into_mysql_database.sh' \
.

Überprüfen Sie ähnliche Frage . Sie könnten die gleiche Schleife in Python versuchen. 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 Schwanz () eine Datei mit Python .

Nun, da Sie Python verwenden, können Sie nur eine Datei öffnen und halte Linien von ihm zu lesen.

f = open('file.log')

Wenn die Zeile gelesen wird nicht leer , können Sie es bearbeiten.

line = f.readline()
if line:
    // Do what you want with the line

Sie können fehlen, dass es ok ist readline am EOF zu halten aufrufen. Es wird nur halten in diesem Fall einen leeren String zurück. Und wenn etwas in die Protokolldatei angehängt wird, wird das Lesen weitermachen, wo es aufgehört, wie Sie benötigen.

Wenn Sie nach einer Lösung suchen, Ereignisse oder einer bestimmten Bibliothek verwendet, bitte geben Sie dies in Ihrer Frage. Ansonsten finde ich diese Lösung nur in Ordnung ist.

Hier ist eine vereinfachte Version von Kender des Code, der den gleichen Trick zu tun scheint und importiert nicht die gesamte Datei:

# Check file for new data.

import time

f = open(r'c:\temp\test.txt', 'r')

while True:

    line = f.readline()
    if not line:
        time.sleep(1)
        print 'Nothing New'
    else:
        print 'Call Function: ', line

Für eine einzelne Datei mit Polling beobachten und minimale Abhängigkeiten, ist hier ein voll fleshed-out Beispiel basierend auf 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

Wie Sie sehen können in Tim Goldens Artikel wies von Horst Gutmann , WIN32 ist relativ komplex und Uhren Verzeichnisse, nicht eine einzelne Datei.

würde Ich mag Sie suchen vorschlagen in Ironpython, die a .NET python-Implementierung. Mit Ironpython können Sie verwenden, um alle die .NET Funktionalität - einschließlich

System.IO.FileSystemWatcher

Welche einzelne Dateien mit einem einfachen Ereignisse Schnittstelle behandelt.

Dies ist eine weitere Modifikation von Tim Goldan des Skript, das auf Linux läuft und fügt einen einfachen Beobachter für Dateiänderung durch eine DIKT (file => Zeit).

Nutzung: 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 ", 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: ", ", ".join(added)
        if removed: print "Removed: ", ", ".join(removed)
        if modified: print "Modified ", ", ".join(modified)

        before = after

Dies ist ein Beispiel für eine Datei für Änderungen zu überprüfen. Eines, das nicht der beste Weg, es zu tun sein kann, aber es ist sicher, dass ein kurzer Weg.

Handy-Tool für den Neustart Anwendung, wenn Änderungen an der Quelle vorgenommen wurden. Ich habe dies, wenn mit pygame spielen, so kann ich Effekte stattfinden, sehen sofort nach Datei speichern.

Wenn in pygame verwendet sicherzustellen, dass das Material in der ‚while‘ Schleife in Ihrer Spielschleife aka Update platziert wird oder was auch immer. Andernfalls Ihre Anwendung wird in einer Endlosschleife hängen bleiben und Sie werden nicht Ihr Spiel Aktualisierung sehen.

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

Falls Sie wollten den Neustart-Code, die ich im Web gefunden. Hier ist es. (Nicht relevant für die Frage, ob es nützlich sein könnte)

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

Haben Sie Spaß machen Elektronen tun, was Sie wollen, dass sie tun.

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

Hier ist ein Beispiel ausgerichtet auf Eingabedateien zu beobachten, die nicht mehr als eine Zeile pro Sekunde, aber in der Regel viel weniger schreiben. Das Ziel ist es die letzte Zeile (letzte Schreiben) an die angegebene Ausgabedatei anhängen. Ich habe dies aus einem meiner Projekte kopiert und nur gelöscht, alle irrelevant Linien. Sie werden in füllen oder die fehlenden Symbole zu ä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 QMainWindow Klasse nicht unbedingt erforderlich, dh. Sie können QFileSystemWatcher allein verwenden.

Die beste und einfachste Lösung ist pygtail zu verwenden:     https://pypi.python.org/pypi/pygtail

from pygtail import Pygtail

while True:
    for line in Pygtail("some.log"):
        sys.stdout.write(line)

Sie können auch eine einfache Bibliothek verwenden genannt repyt , hier ein Beispiel:

repyt ./app.py

Es scheint, dass niemand geschrieben hat fswatch . Es ist eine plattformübergreifende Dateisystemwatcher. Einfach zu installieren, führen Sie es und folgen Sie den Anweisungen.

Ich habe es mit Python und golang Programmen verwendet und es funktioniert einfach.

im Zusammenhang @ 4Oh4 Lösung eine glatte Änderung für eine Liste von Dateien zu sehen;

import os
import sys
import time

class Watcher(object):
    running = True
    refresh_delay_secs = 1

    # Constructor
    def __init__(self, watch_files, call_func_on_change=None, *args, **kwargs):
        self._cached_stamp = 0
        self._cached_stamp_files = {}
        self.filenames = watch_files
        self.call_func_on_change = call_func_on_change
        self.args = args
        self.kwargs = kwargs

    # Look for changes
    def look(self):
        for file in self.filenames:
            stamp = os.stat(file).st_mtime
            if not file in self._cached_stamp_files:
                self._cached_stamp_files[file] = 0
            if stamp != self._cached_stamp_files[file]:
                self._cached_stamp_files[file] = stamp
                # File has changed, so do something...
                file_to_read = open(file, 'r')
                value = file_to_read.read()
                print("value from file", value)
                file_to_read.seek(0)
                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 Exception as e:
                print(e)
                print('Unhandled error: %s' % sys.exc_info()[0])

# Call this function each time a change happens
def custom_action(text):
    print(text)
    # pass

watch_files = ['/Users/mexekanez/my_file.txt', '/Users/mexekanez/my_file1.txt']

# watcher = Watcher(watch_file)  # simple



if __name__ == "__main__":
    watcher = Watcher(watch_files, custom_action, text='yes, changed')  # also call custom action function
    watcher.watch()  # start the watch going

Ich weiß nicht, Windows-spezifische Funktion. Sie könnten versuchen, die MD5-Hash der Datei bekommen jede Sekunde / Minute / Stunde (hängt davon ab, wie schnell Sie sie brauchen) und es bis zum letzten Hash vergleichen. Wenn es unterscheidet wissen, dass Sie die Datei geändert wurde und Sie die neuesten Zeilen ausgelesen werden.

Ich würde versuchen, so etwas wie diese.

    try:
            f = open(filePath)
    except IOError:
            print "No such file: %s" % filePath
            raw_input("Press Enter to close window")
    try:
            lines = f.readlines()
            while True:
                    line = f.readline()
                    try:
                            if not line:
                                    time.sleep(1)
                            else:
                                    functionThatAnalisesTheLine(line)
                    except Exception, e:
                            # handle the exception somehow (for example, log the trace) and raise the same exception again
                            raw_input("Press Enter to close window")
                            raise e
    finally:
            f.close()

Die Schleife überprüft, ob es eine neue Zeile (n) seit dem letzten Mal Datei gelesen wurde - wenn es, es zu lesen und auf die functionThatAnalisesTheLine Funktion übergeben. Wenn nicht, wartet Skript 1 Sekunde und wiederholt den Vorgang.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top