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

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

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

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

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


当前回答

这是对Tim Goldan脚本的另一种修改,它运行在unix类型上,并通过使用dict (file=>time)为文件修改添加了一个简单的监控器。

用法:whatvername .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

其他回答

我不知道任何Windows特有的函数。您可以尝试每秒钟/分钟/小时获取文件的MD5哈希值(取决于您需要它的速度),并将其与最后的哈希值进行比较。当它不同时,您知道文件已被更改,并读取最新的行。

watchfiles (https://github.com/samuelcolvin/watchfiles)是一个Python API和CLI,它使用了用Rust编写的Notify (https://github.com/notify-rs/notify)库。

rust实现目前(2022-10-09)支持:

Linux / Android: inotify macOS: FSEvents或kqueue,参见特性 Windows: ReadDirectoryChangesW FreeBSD / NetBSD / OpenBSD / DragonflyBSD: kqueue 所有平台:投票

可以在PyPI (https://pypi.org/project/watchfiles/)和conda-forge (https://github.com/conda-forge/watchfiles-feedstock)上获得二进制文件。

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

f = open('file.log')

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

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

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

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

正如您在Tim Golden的文章(由Horst Gutmann指出)中看到的,WIN32相对复杂,它监视目录,而不是单个文件。

我建议你研究一下IronPython,它是一个。net python实现。 在IronPython中,你可以使用所有的。net功能——包括

System.IO.FileSystemWatcher

它用一个简单的Event接口处理单个文件。

下面是一个示例,用于观察每秒写入不超过一行但通常要少得多的输入文件。目标是将最后一行(最近的写入)追加到指定的输出文件。我从我的一个项目中复制了这个,只是删除了所有不相关的行。你必须填写或修改缺失的符号。

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

当然,并不是严格要求包含QMainWindow类。您可以单独使用QFileSystemWatcher。