watchdog是最稳妥方案,因它基于系统原生事件机制(如inotify、fsevents),零延迟、低cpu;而手动轮询mtime易漏事件、高cpu、语义模糊且跨平台不一致。

用 watchdog 库是最稳妥的方案,原生轮询(os.stat)仅适合极简场景,且容易漏事件或吃高 CPU。
为什么不用自己轮询文件 mtime?
手动对比 os.stat(path).st_mtime 看起来简单,但实际问题很多:
- 写入未 flush 时,mtime 可能不变(尤其小文件或缓冲写入)
- 高频轮询(如 0.1s 间隔)会显著拉高 CPU;低频轮询(如 2s)又可能错过快速连续写入
- 无法区分“追加”、“覆盖写入”、“清空重写”等语义,回调逻辑难做精准判断
- Windows 下对 NFS 或某些云盘挂载路径,mtime 更新有延迟或不一致
用 watchdog 监听文件变更的最小可行代码
它基于系统原生 inotify(Linux)、kqueue(macOS)、ReadDirectoryChangesW(Windows),事件准确、低开销:
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
<p>class FileChangeHandler(FileSystemEventHandler):
def <strong>init</strong>(self, target_file, callback):
self.target_file = target_file
self.callback = callback</p><pre class="brush:python;toolbar:false;">def on_modified(self, event):
if event.is_directory:
return
if event.src_path == self.target_file:
self.callback(event.src_path)使用示例
def my_callback(filepath): print(f"文件 {filepath} 被修改")
observer = Observer() handler = FileChangeHandler("/path/to/log.txt", my_callback) observer.schedule(handler, path="/path/to", recursive=False) observer.start()
try: observer.join() # 阻塞运行 except KeyboardInterrupt: observer.stop() observer.join()
注意:on_modified 在 Linux/macOS 上对追加写入通常触发一次;Windows 下可能触发多次,需在回调里加简单去重(如记录上一次触发时间戳)。
watchdog 的常见坑与绕过方式
不是所有路径都能监听,也不是所有事件都如预期:
-
/proc、/sys等虚拟文件系统路径无法监听 —— 改用轮询(但慎用,这类文件本就不该被“监听”) - 符号链接默认不跟随 —— 初始化
Observer时传Observer(timeout=1)并确保目标是真实路径,或改用PatternMatchingEventHandler+ 显式os.path.realpath - 日志文件被 logrotate 切割后,原文件句柄失效,新文件不会被监听 —— 必须监听目录级事件(
on_created),再用文件名匹配识别新日志 - 小文件写入(如
echo "x" > file)可能触发on_modified+on_closed_write两个事件 —— 若只需处理最终内容,建议只响应on_closed_write(需继承FileSystemEvent判断事件类型)
真正难的是处理“写入未完成”的情况:比如一个程序正在写大日志,你一读就遇到截断。这得靠业务层加锁、临时后缀、或检查文件是否还在被其他进程打开(fuser / lsof 调用),watchdog 本身不解决这个问题。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










