我有一个日志文件正在写的另一个进程,我想观察变化。每次发生更改时,我都希望将新数据读入并对其进行一些处理。

最好的方法是什么?我希望在PyWin32库中有某种钩子。我找到了win32文件。函数FindNextChangeNotification,但不知道如何要求它监视特定的文件。

如果有人做过类似的事情,我真的很感激能听到…

[编辑]我应该提到我追求的是一种不需要轮询的解决方案。

[编辑]诅咒!这似乎不能在映射的网络驱动器上工作。我猜windows不会像在本地磁盘上那样“听到”任何对文件的更新。


当前回答

因为我已经全局安装了它,所以我最喜欢的方法是使用nodemon。如果你的源代码在src中,你的入口点是src/app.py,那么就像这样简单:

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

... 其中-e py,html允许您控制要监视更改的文件类型。

其他回答

如果轮询对您来说足够好,我只观察“修改的时间”文件统计是否发生变化。阅读方法:

os.stat(filename).st_mtime

(还要注意,Windows本机更改事件解决方案并不在所有情况下都有效,例如在网络驱动器上。)

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

下面是Kender代码的简化版本,它似乎做了同样的技巧,并且没有导入整个文件:

# 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

好吧,因为你在使用Python,你可以打开一个文件,并继续从它读取行。

f = open('file.log')

如果读取的行不是空的,则处理它。

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

您可能忽略了在EOF中继续调用readline是可以的。在这种情况下,它会一直返回空字符串。当将某些内容追加到日志文件时,将根据需要从它停止的地方继续读取。

如果您正在寻找使用事件或特定库的解决方案,请在您的问题中指定。否则,我认为这个解决方案就可以了。

看看我对类似问题的回答。您可以在Python中尝试相同的循环。本页建议:

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

还可以使用Python查看文件中的问题tail()。

为了用轮询和最小依赖来观察单个文件,下面是一个完整的例子,基于Deestan的回答(上面):

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