Bagaimana cara saya menonton file untuk perubahan?

323

Saya memiliki file log yang sedang ditulis oleh proses lain yang ingin saya perhatikan perubahannya. Setiap kali perubahan terjadi, saya ingin membaca data baru untuk melakukan pemrosesan.

Apa cara terbaik untuk melakukan ini? Saya berharap akan ada semacam pengait dari perpustakaan PyWin32. Saya telah menemukan win32file.FindNextChangeNotificationfungsinya tetapi tidak tahu bagaimana cara memintanya menonton file tertentu.

Jika ada yang melakukan hal seperti ini saya akan sangat bersyukur mendengar bagaimana ...

[Sunting] Saya seharusnya menyebutkan bahwa saya mencari solusi yang tidak memerlukan polling.

[Sunting] Kutukan! Tampaknya ini tidak berfungsi pada drive jaringan yang dipetakan. Saya kira windows tidak 'mendengar' pembaruan ke file seperti di disk lokal.

Jon Cage
sumber
1
di Linux kita bisa menggunakan panggilan stracepemantauan writeuntuk ini
test30
Jawaban @ simao menggunakan python-watchdog. Python-Watchdog memiliki dokumentasi yang bagus -> di sini adalah tautan ke dokumentasi ["QuickStart"] yang menyediakan contoh kode minimal yang mengawasi direktori kerja saat ini.
Trevor Boyd Smith

Jawaban:

79

Sudahkah Anda melihat dokumentasi yang tersedia di http://timgolden.me.uk/python/win32_how_do_i/watch_directory_for_changes.html ? Jika Anda hanya membutuhkannya untuk bekerja di bawah Windows, contoh ke-2 tampaknya persis seperti yang Anda inginkan (jika Anda bertukar jalur direktori dengan salah satu file yang ingin Anda tonton).

Kalau tidak, polling mungkin akan menjadi satu-satunya pilihan platform-independen.

Catatan: Saya belum mencoba solusi ini.

Horst Gutmann
sumber
5
Jawaban ini khusus untuk Windows, tetapi tampaknya beberapa solusi lintas platform untuk masalah ini telah diposting di sini juga.
Anderson Green
Apakah ada patokan, jika proses ini lebih lambat maka mengimplementasikannya dalam bahasa asli seperti c ++?
user1767754
Lebih baik untuk memasukkan konten yang relevan dari sumber yang dikutip karena mereka dapat menjadi usang.
Trilarion
2
(1.) di akhir jawaban ini adalah penafian yang kuat ... "Saya belum mencoba solusi ini". (2.) jawaban ini kurang lebih merupakan jawaban "hanya tautan" (3.) jawabannya menyebutkan "polling" tetapi tidak memberikan tambahan apa pun yang bermanfaat setelah itu ... sedangkan jawaban @ Deestan memang memberikan beberapa info bagus tentang polling
Trevor Boyd Smith
283

Apakah Anda mencoba menggunakan Watchdog ?

Pustaka Python API dan utilitas shell untuk memantau acara sistem file.

Pemantauan direktori menjadi mudah

  • API lintas platform.
  • Alat shell untuk menjalankan perintah sebagai respons terhadap perubahan direktori.

Mulai dengan cepat dengan contoh sederhana di Quickstart ...

simao
sumber
56
Diinstal dengan easy_install? Memeriksa. Lisensi gratis? Periksa . Memecahkan masalah pada platform besar? Periksa . Saya mendukung jawaban ini. Hanya catatan: contoh pada halaman proyek mereka tidak bekerja di luar kotak. Gunakan yang di github mereka sebagai gantinya.
Inaimathi
6
Kami menggunakan anjing penjaga. Kami dapat beralih ke QFileSystemWatcher. Hanya pengawas peringatan yang baik tetapi jauh dari sempurna di semua platform (saat ini). Setiap OS memiliki keistimewaan itu. Jadi, kecuali Anda berdedikasi untuk membuatnya sempurna, Anda akan mencabut rambut Anda. Jika Anda hanya ingin menonton 10 file atau lebih, saya akan polling. Caching disk OS sangat matang dan Watchdog melibatkan polling API. Ini terutama untuk menonton struktur folder besar IMHO.
SilentSteel
3
Satu keluhan saya dengan anjing penjaga adalah, ia memiliki banyak ketergantungan. Lebih sedikit daripada PyQt, tentu saja, tetapi tidak berfungsi dan terasa seperti solusi minimal, praktik terbaik, solusi-satu-pekerjaan-dan-lakukan-benar.
AndreasT
1
Apakah @denfromufa benar di sini? Apakah pengawas benar-benar mengunci file, sehingga tidak dapat diedit secara bersamaan untuk menonton pengawas? Saya hampir tidak bisa percaya, itu akan sama sekali tidak berguna.
Michel Müller
1
@ MichelMüller Saya baru saja memeriksa contoh ini (lihat tautan di bawah) dan berfungsi! tidak yakin apa yang salah sebelumnya, tetapi jawaban ini tidak memberikan contoh apa pun. stackoverflow.com/a/18599427/2230844
denfromufa
92

Jika polling cukup baik untuk Anda, saya hanya akan menonton jika stat file "waktu yang diubah" berubah. Untuk membacanya:

os.stat(filename).st_mtime

(Perhatikan juga bahwa solusi peristiwa perubahan asli Windows tidak berfungsi dalam semua keadaan, misalnya pada drive jaringan.)

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
sumber
1
Bagaimana Anda bisa melakukan ini pada suatu interval?
dopatraman
1
@dopatraman Berikut ini adalah bagaimana Anda dapat melakukan ini pada interval `import sys import time pub = Monkey () sementara True: coba: time.sleep (1) pub.watch () kecuali KeyboardInterrupt: print ('\ nDone') istirahat kecuali : print (f'Unhandled error: {sys.exc_info () [0]} ') `
Vlad Bezden
Solusi sederhana yang luar biasa! Saya menambahkan cek untuk menjaga dari pelaporan file berubah di jalankan pertama: if self._cached_stamp is not None.
Noumenon
50

Jika Anda menginginkan solusi multi platform, maka periksa QFileSystemWatcher . Berikut contoh kode (tidak disanitasi):

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
sumber
6
Saya pikir ini sangat mungkin jawaban terbaik dari kelompok tersebut mengingat bahwa mereka a) bergantung pada objek FileSystemwatcher Win32 dan tidak dapat porting atau b) polling untuk file (yang buruk untuk kinerja dan tidak akan skala). Sayang sekali Python tidak memiliki fasilitas ini karena PyQt adalah ketergantungan yang sangat besar jika semua yang Anda gunakan adalah kelas QFileSystemWatcher.
CadentOrange
4
Saya suka solusi ini. Saya ingin menunjukkan bahwa Anda akan memerlukan instance QApplication agar bisa berfungsi, saya menambahkan "app = QtGui.QApplication (sys.argv)" tepat di bawah impor dan kemudian "app.exec_ ()" setelah koneksi sinyal.
spencewah
Hanya menguji ini pada kotak Linux, saya melihat bahwa metode directory_changed dipanggil, tetapi tidak file_changed.
Ken Kinder
@CadentOrange, jika Anda tidak suka ketergantungan PyQt, yang watchdogpaket adalah jawaban yang tepat
Mike Pennington
mengapa tidak menggunakannya PySideuntuk itu alih-alih PyQtuntuk penggunaan sekecil itu.
Ciasto piekarz
29

Seharusnya tidak bekerja di windows (mungkin dengan cygwin?), Tetapi untuk pengguna unix, Anda harus menggunakan panggilan sistem "fcntl". Berikut ini adalah contoh dalam Python. Sebagian besar kode yang sama jika Anda perlu menuliskannya dalam C (nama fungsi yang sama)

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
sumber
3
Bekerja seperti pesona dengan kernel Linux 2.6.31 pada sistem file ext4 (pada Ubuntu 10.04), meskipun hanya untuk direktori - ia memunculkan IOError "bukan direktori" jika saya menggunakannya dengan file.
David Underhill
1
BAGUS! Sama bagi saya, hanya berfungsi untuk direktori dan menonton file di direktori ini. Tapi itu tidak akan berfungsi untuk file yang dimodifikasi di subdirektori, jadi sepertinya Anda harus berjalan melewati subdirektori dan menonton semuanya. (atau adakah cara yang lebih baik untuk melakukan ini?)
lfagundes
20

Lihat pyinotify .

inotify menggantikan dnotify (dari jawaban sebelumnya) di linux yang lebih baru dan memungkinkan tingkat file daripada pemantauan tingkat direktori.

Michael Palmer
sumber
5
Bukan untuk meredam jawaban ini, tetapi setelah membaca artikel ini, saya akan mengatakan bahwa itu mungkin bukan solusi glamor seperti yang dipikirkan. serpentine.com/blog/2008/01/04/why-you-should-not-use-pyinotify
NuclearPeon
1
pyinotify memiliki banyak kelemahan mulai dari basis kode yang sangat unpythonic hingga konsumsi memori. Lebih baik mencari opsi lain ..
Tyto
13

Nah setelah sedikit peretasan skrip Tim Golden, saya memiliki yang berikut ini yang tampaknya bekerja dengan baik:

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 )

Ini mungkin bisa dilakukan dengan memuat lebih banyak pengecekan kesalahan, tetapi untuk hanya menonton file log dan melakukan beberapa pemrosesan sebelum meludahkannya ke layar, ini bekerja dengan baik.

Terima kasih semuanya atas masukan Anda - hal-hal hebat!

Jon Cage
sumber
10

Untuk menonton satu file dengan polling, dan dependensi minimal, berikut adalah contoh yang sepenuhnya diperlengkapi, berdasarkan jawaban dari Deestan (di atas):

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
sumber
2
Anda bisa membuat watch_filedan _cached_stampmasuk ke dalam daftar, dan beralih di dalamnya dalam for loop. Tidak benar-benar skala baik untuk sejumlah besar file
4Oh4
Bukankah ini memicu tindakan setiap kali dijalankan? _cached_stamp diatur ke 0 dan kemudian dibandingkan dengan os.stat (self.filename) .st_mtime. _cached_stamp harus disetel ke os.stat (self.filename) .st_mtime di konstruktor, bukan?
Seanonymous
1
call_func_on_change()akan dipicu pada jalankan pertama look(), tetapi kemudian _cached_stampdiperbarui, jadi tidak akan terpicu lagi hingga nilai os.stat(self.filename).st_mtime. _cached_stampperubahan.
4Oh4
1
Anda dapat mengatur nilai _cached_stampdalam konstruktor jika Anda tidak ingin call_func_on_change()dipanggil pada jalankan pertama
4Oh4
Saya telah menggunakan skrip Anda untuk memanggil beberapa fungsi pada perubahan file. Fungsi saya tidak mengambil argumen seperti milik Anda. Saya berpikir bahwa untuk membuatnya berfungsi, saya perlu menghapus * args, ** kwargs Tampaknya (saya hanya menempatkan baris dengan perubahan): self.call_func_on_change(self) def custom_action(): watcher = Watcher(watch_file, custom_action())Tapi ini tidak berhasil. Tindakan hanya dipanggil selama iterasi pertama: File berubah ya, diubah File berubah File berubah File berubah Itu mulai bekerja ketika saya menyimpan * argumen dan menyebutnya: watcher = Watcher(watch_file, custom_action)Saya kesulitan bertanya-tanya mengapa?
zwornik
7

Periksa jawaban saya untuk pertanyaan serupa . Anda bisa mencoba loop yang sama dengan Python. Halaman ini menyarankan:

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

Lihat juga tail pertanyaan () file dengan Python .

Bruno De Fraine
sumber
Anda dapat sys.stdout.write (baris). Kode Anda tidak berfungsi jika file terpotong. Python memiliki file fungsi builtin ().
jfs
Saya telah memasang versi kode Anda yang dimodifikasi. Anda dapat memasukkannya dalam jawaban Anda jika itu bekerja untuk Anda.
jfs
7

Solusi paling sederhana bagi saya adalah menggunakan alat pengawas watchmedo

Dari https://pypi.python.org/pypi/watchdog sekarang saya memiliki proses yang mencari file sql dalam direktori dan mengeksekusi mereka jika perlu.

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

Nah, karena Anda menggunakan Python, Anda bisa membuka file dan terus membaca baris darinya.

f = open('file.log')

Jika baris yang dibaca tidak kosong , Anda memprosesnya.

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

Anda mungkin kehilangan bahwa tidak masalah untuk terus menelepon readline di EOF. Ini hanya akan terus mengembalikan string kosong dalam kasus ini. Dan ketika sesuatu ditambahkan ke file log, bacaan akan dilanjutkan dari tempat itu berhenti, seperti yang Anda butuhkan.

Jika Anda mencari solusi yang menggunakan acara, atau perpustakaan tertentu, harap tentukan ini di pertanyaan Anda. Kalau tidak, saya pikir solusi ini baik-baik saja.

seuvitor
sumber
6

Ini adalah versi sederhana dari kode Kender yang tampaknya melakukan trik yang sama dan tidak mengimpor seluruh file:

# 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
sumber
6

Ini adalah modifikasi lain dari skrip Tim Goldan yang berjalan pada tipe unix dan menambahkan pengamat sederhana untuk modifikasi file dengan menggunakan dict (file => waktu).

penggunaan: 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
sumber
Diperbarui untuk mendukung python3
ronedg
4

Seperti yang dapat Anda lihat di artikel Tim Golden , ditunjukkan oleh Horst Gutmann , WIN32 relatif kompleks dan mengawasi direktori, bukan satu file.

Saya ingin menyarankan Anda melihat ke IronPython , yang merupakan implementasi .NET python. Dengan IronPython Anda dapat menggunakan semua fungsionalitas .NET - termasuk

System.IO.FileSystemWatcher

Yang menangani file tunggal dengan antarmuka Acara sederhana .

Gimel
sumber
@ Ciasto karena Anda harus memiliki Iron Python tersedia daripada instalasi Python dasar.
Jon Cage
1

Ini adalah contoh memeriksa file untuk perubahan. Cara yang mungkin bukan cara terbaik untuk melakukannya, tetapi tentu saja ini cara yang singkat.

Alat praktis untuk memulai ulang aplikasi ketika ada perubahan pada sumbernya. Saya membuat ini ketika bermain dengan pygame sehingga saya dapat melihat efeknya terjadi segera setelah file disimpan.

Saat digunakan dalam pygame pastikan barang-barang di loop 'while' ditempatkan di loop game Anda alias perbarui atau apa pun. Kalau tidak, aplikasi Anda akan macet dalam loop tak terbatas dan Anda tidak akan melihat pembaruan game Anda.

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

Jika Anda menginginkan kode restart yang saya temukan di web. Ini dia. (Tidak relevan dengan pertanyaan, meskipun bisa berguna)

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

Bersenang-senang membuat elektron melakukan apa yang Anda inginkan.

Bassim Huis
sumber
Sepertinya menggunakan .st_mtimedaripada .st_sizeakan lebih dapat diandalkan dan cara yang sama singkatnya untuk melakukan ini, meskipun OP telah mengindikasikan bahwa ia tidak ingin melakukannya melalui polling.
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
sumber
1

Berikut adalah contoh diarahkan menonton file input yang menulis tidak lebih dari satu baris per detik tetapi biasanya jauh lebih sedikit. Tujuannya adalah untuk menambahkan baris terakhir (paling baru tulis) ke file output yang ditentukan. Saya telah menyalin ini dari salah satu proyek saya dan baru saja menghapus semua baris yang tidak relevan. Anda harus mengisi atau mengubah simbol yang hilang.

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

Tentu saja, kelas QMainWindow yang melingkupi tidak sepenuhnya diperlukan, yaitu. Anda bisa menggunakan QFileSystemWatcher sendirian.


sumber
0

Anda juga dapat menggunakan pustaka sederhana bernama repyt , berikut ini sebuah contoh:

repyt ./app.py
Rafal Enden
sumber
0

Tampaknya tidak ada yang memposting fswatch . Ini adalah pengamat sistem file lintas platform. Instal saja, jalankan dan ikuti petunjuknya.

Saya sudah menggunakannya dengan program python dan golang dan hanya berfungsi.

Gus
sumber
0

solusi terkait @ 4Oh4 perubahan halus untuk daftar file untuk ditonton;

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
sumber
0

Solusi terbaik dan paling sederhana adalah dengan menggunakan 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
sumber
-2

Saya tidak tahu fungsi khusus Windows. Anda bisa mencoba mendapatkan hash MD5 file setiap detik / menit / jam (tergantung seberapa cepat Anda membutuhkannya) dan membandingkannya dengan hash terakhir. Ketika berbeda, Anda tahu file telah diubah dan Anda membacakan baris terbaru.

scable
sumber
-6

Saya akan mencoba sesuatu seperti ini.

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

Loop memeriksa apakah ada baris baru sejak file terakhir kali dibaca - jika ada, itu dibaca dan diteruskan ke functionThatAnalisesTheLinefungsi. Jika tidak, skrip menunggu 1 detik dan coba lagi prosesnya.

kender
sumber
4
-1: Membuka file dan membaca baris bukan ide bagus ketika file bisa 100-an dari MB besar. Anda harus menjalankannya untuk setiap file juga yang akan menjadi buruk ketika Anda ingin menonton 1000 file.
Jon Cage
1
Betulkah? Membuka file untuk perubahan?
Farsheed