watchdog默认不递归监控子目录且事件回调阻塞后续事件;需设recursive=true监听全目录树,用绝对路径或pathlib.path,过滤文件类型、去重延时合并修改事件,耗时操作应交由线程池处理。

watchdog 能实时捕获文件增删改事件,但默认不递归监控子目录,且事件回调里做耗时操作会阻塞后续事件——这是最常踩的两个坑。
如何监听指定路径下的所有文件变化(含子目录)
watchdog 默认只监控顶层目录,要监控整个目录树必须显式启用 recursive=True。否则新增子目录或其内部文件变动完全收不到事件。
实操建议:
- 创建
Observer实例后,调用schedule()时务必传入recursive=True - 路径参数用
pathlib.Path或绝对路径,避免相对路径在 daemon 化时失效 - 若只需监控某几类文件(如
.py和.txt),可在自定义FileSystemEventHandler的on_modified()中加if event.src_path.endswith(('.py', '.txt')):过滤
为什么修改一个文件会触发多次 on_modified?
常见于编辑器(如 VS Code、Sublime)保存时:先写临时文件,再原子替换原文件,导致 on_modified + on_moved 组合出现;或者某些程序分块写入,触发多次修改事件。
实操建议:
- 不要在
on_modified()里直接处理业务逻辑,改用去重+延时合并策略 - 用
time.time()记录上次处理时间,同路径 100ms 内重复事件直接跳过 - 对
event.is_directory == False做判断,避免误处理目录事件
如何安全地在事件回调中执行耗时操作(如上传、解析)
watchdog 的事件线程是单线程异步分发的,如果在 on_created() 里直接调用 requests.post() 或读大文件,会导致后续事件堆积甚至丢失。
实操建议:
- 用
threading.Thread启动新线程处理,但注意线程安全(比如共享日志对象需加锁) - 更稳妥的是用
concurrent.futures.ThreadPoolExecutor管理线程池,限制并发数防资源耗尽 - 切勿在回调里调用
time.sleep()或阻塞 IO,这是最典型的卡死原因
真正难的不是启动监听,而是应对编辑器保存策略、NFS 挂载延迟、权限变更等边缘情况;建议在 on_any_event() 里打日志,先跑一整天看真实事件流再决定过滤逻辑。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











