Wie überprüfe ich eine Datei auf Änderungen?

322

Ich habe eine Protokolldatei, die von einem anderen Prozess geschrieben wird und auf Änderungen achten 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 Hook aus der PyWin32-Bibliothek geben würde. Ich habe die win32file.FindNextChangeNotificationFunktion gefunden, habe aber keine Ahnung, wie ich sie bitten soll, eine bestimmte Datei anzusehen.

Wenn jemand so etwas getan hat, wäre ich wirklich dankbar zu hören, wie ...

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

[Bearbeiten] Flüche! Es scheint, dass dies über ein zugeordnetes Netzlaufwerk nicht funktioniert. Ich vermute, Windows "hört" keine Aktualisierungen der Datei wie auf einer lokalen Festplatte.

Jon Cage
quelle
1
unter Linux könnte man verwenden , die straceÜberwachung writedieser Anrufe für
test30
@ simaos Antwort verwendet Python-Watchdog. Python-Watchdog hat eine großartige Dokumentation -> hier ist ein Link zur ["QuickStart"] - Dokumentation, die ein minimales Codebeispiel enthält, das das aktuelle Arbeitsverzeichnis überwacht.
Trevor Boyd Smith

Antworten:

79

Haben Sie sich bereits die Dokumentation unter http://timgolden.me.uk/python/win32_how_do_i/watch_directory_for_changes.html angesehen ? Wenn Sie es nur benötigen, um unter Windows zu funktionieren, scheint das zweite Beispiel genau das zu sein, was Sie möchten (wenn Sie den Pfad des Verzeichnisses mit dem der Datei austauschen, die Sie überwachen möchten).

Andernfalls ist die Abfrage wahrscheinlich die einzige wirklich plattformunabhängige Option.

Hinweis: Ich habe keine dieser Lösungen ausprobiert.

Horst Gutmann
quelle
5
Diese Antwort ist Windows-spezifisch, aber es scheint, dass hier auch einige plattformübergreifende Lösungen für dieses Problem veröffentlicht wurden.
Anderson Green
Gibt es einen Benchmark, wenn dieser Prozess langsamer ist als die Implementierung in einer Muttersprache wie c ++?
user1767754
Es ist besser, die relevanten Inhalte aus zitierten Quellen einzufügen, da diese veraltet sein können.
Trilarion
2
(1.) Am Ende dieser Antwort steht ein starker Haftungsausschluss ... "Ich habe keine dieser Lösungen ausprobiert". (2.) Diese Antwort ist mehr oder weniger eine "Nur-Link" -Antwort. (3.) In der Antwort wird "Polling" erwähnt, aber danach wird nichts Hilfreiches hinzugefügt ... wobei die Antwort von @ Deestan einige gute Informationen zum Polling enthält
Trevor Boyd Smith
282

Haben Sie versucht, Watchdog zu verwenden ?

Python-API-Bibliothek und Shell-Dienstprogramme zum Überwachen 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 Quickstart ...

simao
quelle
56
Installierbar mit easy_install? Prüfen. Freie Lizenz? Überprüfen Sie . Löst das Problem auf den großen Plattformen? Überprüfen Sie . Ich unterstütze diese Antwort. Einziger Hinweis: Das Beispiel auf der Projektseite funktioniert nicht sofort. Verwenden Sie stattdessen die auf ihrem Github .
Inaimathi
6
Wir benutzen Watchdog. Wir können zu QFileSystemWatcher wechseln. Nur ein fairer Warnhund ist gut, aber auf allen Plattformen (zu diesem Zeitpunkt) alles andere als perfekt. Jedes Betriebssystem hat seine Besonderheiten. Wenn Sie sich nicht dafür einsetzen, es perfekt zu machen, werden Sie sich die Haare ausreißen. Wenn Sie nur 10 Dateien oder so ansehen möchten, würde ich eine Umfrage durchführen. Das Zwischenspeichern von Betriebssystemdatenträgern ist sehr ausgereift und Watchdog beinhaltet sowieso das Abrufen von APIs. Es ist hauptsächlich für das Betrachten großer Ordnerstrukturen IMHO.
SilentSteel
3
Mein einziger Kritikpunkt am Watchdog ist, dass er viele Abhängigkeiten hat. Natürlich weniger als PyQt, aber es funktioniert nicht und fühlt sich nicht wie die minimale, bewährte Methode an, die nur einen Job erledigt und es richtig macht.
AndreasT
1
Ist @denfromufa hier korrekt? Sperrt Watchdog wirklich Dateien, sodass sie nicht gleichzeitig bearbeitet werden können, um Watchdog zu beobachten? Ich kann das kaum glauben, es wäre völlig nutzlos.
Michel Müller
1
@ 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 liefert kein Beispiel. stackoverflow.com/a/18599427/2230844
denfromufa
92

Wenn die Abfrage für Sie gut genug ist, würde ich nur beobachten, ob sich der Status der Datei "Geänderte Zeit" ändert. Um es zu lesen:

os.stat(filename).st_mtime

(Beachten Sie auch, dass die native Windows-Änderungsereignislösung nicht unter allen Umständen funktioniert, z. B. auf Netzwerklaufwerken.)

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...
Deestan
quelle
1
Wie können Sie dies in einem Intervall tun?
Dopatraman
1
@dopatraman So können Sie dies in einem Intervall tun: `import sys import time pub = Monkey () während True: try: time.sleep (1) pub.watch () außer KeyboardInterrupt: print ('\ nDone') break außer : print (f'Unhandled error: {sys.exc_info () [0]} ') `
Vlad Bezden
Tolle einfache Lösung! Ich habe eine Überprüfung hinzugefügt, um zu verhindern, dass die beim ersten Start geänderte Datei gemeldet wird : if self._cached_stamp is not None.
Noumenon
50

Wenn Sie eine plattformübergreifende Lösung wünschen, überprü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)
hipersayan_x
quelle
6
Ich denke, dass dies wahrscheinlich die beste Antwort ist, da sie entweder a) auf das FileSystemwatcher-Objekt von Win32 angewiesen sind und nicht portiert werden können oder b) nach der Datei abfragen (was für die Leistung schlecht ist und nicht skaliert). Schade, dass Python diese Funktion nicht eingebaut hat, da PyQt eine große Abhängigkeit darstellt, wenn Sie nur die QFileSystemWatcher-Klasse verwenden.
CadentOrange
4
Ich mag diese Lösung. Ich wollte darauf hinweisen, dass Sie eine QApplication-Instanz benötigen, damit sie funktioniert. Ich habe "app = QtGui.QApplication (sys.argv)" direkt unter den Importen und dann "app.exec_ ()" nach den Signalverbindungen hinzugefügt.
Spencewah
Wenn ich dies nur auf einer Linux-Box teste, sehe ich, dass die Methode directory_changed aufgerufen wird, nicht jedoch file_changed.
Ken Kinder
@ CadentOrange, wenn Sie die pyQt-Abhängigkeit nicht mögen, ist das watchdogPaket die richtige Antwort
Mike Pennington
warum nicht PySidedafür anstatt PyQtfür so einen kleinen Gebrauch verwenden.
Ciasto piekarz
29

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)
Maxime
quelle
3
Funktioniert wie ein Zauber mit dem Linux-Kernel 2.6.31 auf einem ext4-Dateisystem (unter Ubuntu 10.04), allerdings nur für Verzeichnisse - es löst einen IOError "kein Verzeichnis" aus, wenn ich ihn mit einer Datei verwende.
David Underhill
1
GROSS! Das gleiche gilt für mich, funktioniert nur für Verzeichnisse und überwacht Dateien in diesem Verzeichnis. Es funktioniert jedoch nicht für geänderte Dateien in Unterverzeichnissen. Es sieht also so aus, als müssten Sie durch die Unterverzeichnisse gehen und alle ansehen. (oder gibt es einen besseren Weg, dies zu tun?)
lfagundes
20

Schauen Sie sich pyinotify an .

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

Michael Palmer
quelle
5
Um diese Antwort nicht zu dämpfen, aber nachdem ich diesen Artikel gelesen habe, würde ich sagen, dass es möglicherweise keine so glamouröse Lösung ist wie gedacht. serpentine.com/blog/2008/01/04/why-you-should-not-use-pyinotify
NuclearPeon
1
pyinotify hat viele Nachteile, angefangen von einer sehr unpythonischen Codebasis bis hin zum Speicherverbrauch. Besser nach anderen Optionen suchen ..
Tyto
13

Nun, nach einigem Hacken von Tim Goldens Drehbuch 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 mit einer weiteren Fehlerprüfung verbunden sein, aber wenn Sie einfach eine Protokolldatei ansehen und sie bearbeiten, bevor Sie sie auf den Bildschirm ausspucken, funktioniert dies gut.

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

Jon Cage
quelle
10

Um eine einzelne Datei mit Abfragen und minimalen Abhängigkeiten anzusehen , finden Sie hier ein ausführliches 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
4Oh4
quelle
2
Sie könnten machen watch_fileund _cached_stampin Listen und Iterierte über sie in einer for - Schleife. Skaliert nicht wirklich gut auf eine große Anzahl von Dateien
4Oh4
Löst dies die Aktion nicht jedes Mal aus, wenn sie 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 sein, nein?
Seanonymous
1
call_func_on_change()wird beim ersten Durchlauf von ausgelöst look(), wird dann _cached_stampaber aktualisiert und wird erst wieder ausgelöst, wenn sich der Wert von os.stat(self.filename).st_mtime. _cached_stampändert.
4Oh4
1
Sie können den Wert von _cached_stampim Konstruktor festlegen, wenn Sie call_func_on_change()beim ersten Lauf nicht aufgerufen werden möchten
4Oh4
Ich habe Ihr Skript verwendet, um eine Funktion zum Ändern von Dateien aufzurufen. Meine Funktion akzeptiert keine anderen Argumente als Ihre. Ich dachte, damit es funktioniert, muss ich * args, ** kwargs entfernen. 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 begann zu funktionieren, als ich * args behielt und es aufrief: watcher = Watcher(watch_file, custom_action)Ich habe Mühe, mich zu fragen, warum?
zwornik
7

Überprüfen Sie meine Antwort auf eine ähnliche Frage . Sie können dieselbe 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 () einer Datei mit Python .

Bruno De Fraine
quelle
Sie können Sie sys.stdout.write (Zeile). Ihr Code funktioniert nicht, wenn die Datei abgeschnitten ist. Python hat eine eingebaute Funktionsdatei ().
JFS
Ich habe eine modifizierte Version Ihres Codes veröffentlicht. Sie können es in Ihre Antwort aufnehmen, wenn es für Sie funktioniert.
JFS
7

Die einfachste Lösung für mich ist die Verwendung des Watchdog-Tools watchmedo

Unter https://pypi.python.org/pypi/watchdog habe ich jetzt einen Prozess, der die SQL-Dateien in einem Verzeichnis sucht und sie bei Bedarf ausführt.

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

Nun, da Sie Python verwenden, können Sie einfach eine Datei öffnen und weiterhin Zeilen daraus lesen.

f = open('file.log')

Wenn die gelesene Zeile nicht leer ist , verarbeiten Sie sie.

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

Möglicherweise fehlt Ihnen, dass es in Ordnung ist, weiterhin readlinebeim EOF anzurufen. In diesem Fall wird nur eine leere Zeichenfolge zurückgegeben. Und wenn etwas an die Protokolldatei angehängt wird, wird der Lesevorgang nach Bedarf dort fortgesetzt, wo er gestoppt wurde.

Wenn Sie nach einer Lösung suchen, die Ereignisse oder eine bestimmte Bibliothek verwendet, geben Sie dies bitte in Ihrer Frage an. Ansonsten denke ich, dass diese Lösung in Ordnung ist.

Seuvitor
quelle
6

Hier ist eine vereinfachte Version von Kenders Code, die anscheinend denselben Trick ausführt und nicht die gesamte Datei importiert:

# 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
AlaXul
quelle
6

Dies ist eine weitere Modifikation von Tim Goldans Skript, das unter Unix-Typen ausgeführt wird und einen einfachen Watcher für die Dateimodifikation mithilfe eines Diktats (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
ronedg
quelle
Aktualisiert, um python3 zu unterstützen
ronedg
4

Wie Sie in Tim Goldens Artikel sehen können , auf den Horst Gutmann hingewiesen hat, ist WIN32 relativ komplex und überwacht Verzeichnisse, nicht eine einzige Datei.

Ich möchte vorschlagen, dass Sie sich mit IronPython befassen , einer .NET- Python-Implementierung. Mit IronPython können Sie alle .NET- Funktionen nutzen - auch

System.IO.FileSystemWatcher

Welches behandelt einzelne Dateien mit einer einfachen Ereignisschnittstelle .

gimel
quelle
@Ciasto, weil dann Iron Python verfügbar sein muss und keine grundlegende Python-Installation.
Jon Cage
1

Dies ist ein Beispiel für das Überprüfen einer Datei auf Änderungen. Eine, die vielleicht nicht der beste Weg ist, aber es ist sicher ein kurzer Weg.

Praktisches Tool zum Neustarten der Anwendung, wenn Änderungen an der Quelle vorgenommen wurden. Ich habe dies beim Spielen mit Pygame gemacht, damit ich sofort nach dem Speichern der Datei Effekte sehen kann.

Wenn Sie in Pygame verwendet werden, stellen Sie sicher, dass sich das Material in der 'while'-Schleife in Ihrer Spieleschleife befindet, auch bekannt als Update oder was auch immer. Andernfalls bleibt Ihre Anwendung in einer Endlosschleife stecken und Sie werden nicht sehen, wie 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 Neustartcode wollten, den ich im Web gefunden habe. Hier ist es. (Nicht relevant für die Frage, obwohl es nützlich sein könnte)

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

Viel Spaß damit, dass Elektronen das tun, was Sie wollen.

Bassim Huis
quelle
Es scheint, als wäre die Verwendung .st_mtimeanstelle von .st_sizezuverlässiger und eine ebenso kurze Möglichkeit, dies zu tun, obwohl das OP angegeben hat, dass er dies nicht über Umfragen tun wollte.
Martineau
1
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
                ...
imp
quelle
1

Hier ist ein Beispiel, das darauf ausgerichtet ist, Eingabedateien anzusehen, die nicht mehr als eine Zeile pro Sekunde, aber normalerweise viel weniger schreiben. Ziel ist es, die letzte Zeile (letzter Schreibvorgang) an die angegebene Ausgabedatei anzuhängen. Ich habe dies aus einem meiner Projekte kopiert und gerade 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 QMainWindow-Klasse nicht unbedingt erforderlich, d. H. Sie können QFileSystemWatcher allein verwenden.


quelle
0

Sie können auch eine einfache Bibliothek namens repyt verwenden . Hier ein Beispiel:

repyt ./app.py
Rafal Enden
quelle
0

Scheint, dass niemand fswatch gepostet hat . Es ist ein plattformübergreifender Dateisystem-Watcher. Installieren Sie es einfach, führen Sie es aus und befolgen Sie die Anweisungen.

Ich habe es mit Python- und Golang-Programmen verwendet und es funktioniert einfach.

Gus
quelle
0

verwandte @ 4Oh4-Lösung eine reibungslose Änderung für eine Liste der zu beobachtenden Dateien;

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
mexekanez
quelle
0

Die beste und einfachste Lösung ist die Verwendung von Pygtail: https://pypi.python.org/pypi/pygtail

from pygtail import Pygtail
import sys

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

Ich kenne keine Windows-spezifische Funktion. Sie können versuchen, den MD5-Hash der Datei jede Sekunde / Minute / Stunde abzurufen (abhängig davon, wie schnell Sie ihn benötigen) und ihn mit dem letzten Hash zu vergleichen. Wenn es anders ist, wissen Sie, dass die Datei geändert wurde und Sie lesen die neuesten Zeilen aus.

scable
quelle
-6

Ich würde so etwas versuchen.

    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 prüft, ob seit dem letzten Lesen der Datei eine oder mehrere neue Zeilen vorhanden sind. Wenn dies der Fall ist, wird diese gelesen und an die functionThatAnalisesTheLineFunktion übergeben. Wenn nicht, wartet das Skript 1 Sekunde und wiederholt den Vorgang.

Kender
quelle
4
-1: Das Öffnen der Datei und das Lesen von Zeilen ist keine gute Idee, wenn die Dateien 100 MB groß sein könnten. Sie müssten es auch für jede einzelne Datei ausführen, was schlecht wäre, wenn Sie Tausende von Dateien ansehen möchten.
Jon Cage
1
"Ja wirklich?" Datei für Änderungen öffnen?
Farsheed