watchdog比轮询更可靠,因其基于系统原生事件机制(linux inotify/macos fsevents/windows readdirectorychangesw),实现毫秒级响应、零cpu空转、精准区分创建/修改/重命名等事件,而轮询易漏事件、高开销且无法识别操作类型。

用 watchdog 监控文件变化比轮询更可靠
轮询(比如每秒检查 os.path.getmtime())在高频率或大目录下容易漏事件、耗 CPU,且无法区分“修改”“创建”“重命名”。watchdog 基于系统原生 inotify(Linux)、FSEvents(macOS)、ReadDirectoryChangesW(Windows),事件精准、低开销。
安装后直接监听目标路径:
pip install watchdog
关键点:
-
FileSystemEventHandler子类中重写on_modified()、on_created()等方法,不要只依赖on_any_event() - 监控目录需存在,
recursive=True才能捕获子目录内变化 - 事件对象的
event.src_path是绝对路径,注意判断是否为文件(event.is_directory == False) - 同一文件连续保存可能触发多次
on_modified,建议加简单去重(如 100ms 内相同路径忽略)
处理刚写入的文件要防“读取冲突”
编辑器保存文件时,常先清空再写入(如 VS Code),或先写临时文件再原子替换(如 mv tmpfile target)。直接在 on_modified 里读文件,可能遇到空文件、权限拒绝或 PermissionError。
稳妥做法:
- 对
on_created或on_modified事件,先用os.path.exists()和os.access(path, os.R_OK)检查可读性 - 加小延迟再读(如
time.sleep(0.1)),或用重试循环(最多 3 次,每次间隔 0.2s) - 若业务允许,优先监听
on_moved—— 原子写入通常表现为“临时文件 moved to target”,此时文件已就绪
避免阻塞主线程导致事件丢失
watchdog 默认在单独线程派发事件,但如果你在 on_modified 里做耗时操作(如解析大 CSV、调外部 API),会积压事件队列,甚至丢事件。
必须解耦处理逻辑:
- 事件回调里只做轻量操作:把
event.src_path推进queue.Queue或asyncio.Queue - 另起一个工作线程/协程消费队列,执行实际业务逻辑
- 别在回调里直接
time.sleep()或requests.post()—— 这等于给事件循环“踩刹车”
Windows 下要注意长路径和符号链接
Windows 默认路径长度限制为 260 字符,监控深层嵌套目录时可能报 WindowsError: [Error 206] The filename or extension is too long。启用长路径支持只是第一步,watchdog 还需额外配置:
- 确保 Python 启动前已开启组策略“启用 Win32 长路径”(
Computer Configuration → Administrative Templates → System → Filesystem) - 初始化
Observer时传参timeout=1.0(默认 0 可能在某些 NTFS 配置下卡住) - 符号链接默认不跟踪目标内容,需显式设置
follow_symlinks=True,但会失去对链接本身变更的感知
跨平台部署时,event.event_type 的值(如 'modified')一致,但底层行为差异仍在——比如 macOS 的 FSEvents 对硬链接不敏感,而 inotify 会触发两次。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











