watchdog是唯一成熟封装inotify、ReadDirectoryChangesW、FSEvents的Python库,基于操作系统原生事件驱动,非轮询,可精准捕获创建/修改/重命名等底层文件系统事件。

用 watchdog 监听文件夹变化最可靠
Windows 资源管理器的“实时同步”或简单轮询 os.listdir() 都不可靠:前者不跨平台、无事件精度;后者消耗 CPU 且漏事件。真正能捕获创建/修改/重命名等底层事件的,只有基于操作系统 inotify(Linux)、ReadDirectoryChangesW(Windows)、FSEvents(macOS)的库。watchdog 就是唯一成熟封装这三者的 Python 库,它不是 polling,是真正的 event-driven。
安装后直接监听即可,无需手动处理平台差异:
pip install watchdog
关键点:
-
FileSystemEventHandler子类中重写on_created,不是on_modified—— 新增文件触发的是created事件,哪怕你用复制粘贴方式放入 - 必须调用
observer.start()后再join(),否则主线程退出导致监听静默终止 - 监听路径末尾不加斜杠(
"D:/source"✅,"D:/source/"❌),部分系统会因路径规范化失败而静默跳过
同步新增文件前先校验是否完整写入
很多脚本一收到 on_created 就立刻复制,结果得到零字节或截断文件——因为某些程序(如 Excel、微信下载)先创建空文件,再流式写入内容,事件到达时写入尚未完成。
稳妥做法是加一个轻量级等待和校验逻辑:
- 用
os.path.getsize()检查文件大小是否在 1–2 秒内稳定(连续两次读取值相同) - 对大文件(>10MB)额外加
time.sleep(0.5)避免频繁 stat - 跳过临时文件:
if event.src_path.endswith(('.tmp', '.part', '~')): - 不要用
shutil.copy2()直接覆盖目标——若备份盘已存在同名文件但时间戳更新,应比对os.path.getmtime()再决定是否覆盖
Windows 下备份盘路径需用 UNC 或驱动器号显式声明
Python 的 shutil.copy2() 在 Windows 上对网络映射盘(如 Z:ackup)偶尔失败,报错 PermissionError: [WinError 5] Access is denied,尤其当脚本以非交互方式运行(如任务计划程序)时。
librosa 是一个用于音频和音乐分析的 Python 库。它提供了特征提取、频谱分析、节拍跟踪、起始检测和音频可视化的工具,基于 NumPy 和 SciPy 构建,用于科学音频计算。
根本原因是 Windows 网络驱动器映射属于用户会话上下文,服务或后台进程看不到。解决方法只有两个:
- 改用 UNC 路径:
r"\NASackupolder"(注意 raw string 和双反斜杠) - 或确保备份盘是物理/本地驱动器(如
D:ackup),且脚本有该盘符的读写权限 - 绝对不要依赖
os.getcwd()或相对路径拼接目标——同步脚本常被调度器在任意目录启动,路径必须绝对且硬编码或从配置读取
避免重复同步和死循环
如果你把备份目录也加入监听范围,或者同步过程本身触发新事件(比如 copy2 会写入访问时间),就可能形成“监听 → 同步 → 新事件 → 再监听 → 再同步”的死循环。
必须切断这个链路:
- 监听时排除备份目录:
observer.schedule(handler, path="D:/source", recursive=True),别写成"D:/" - 同步操作完成后,给目标文件加只读属性(
os.chmod(dst_path, stat.S_RDONLY))可阻止多数编辑器二次保存触发修改事件 - 更彻底的方式:在
on_created中记录已处理的event.src_path + timestamp到内存 set 或小文件,10 秒内重复事件直接忽略(适用于高频小文件场景)
实际部署时,最易被忽略的是权限与上下文隔离——计划任务默认没 GUI 会话,无法访问映射盘;Docker 容器里没 inotify 支持;WSL2 监听 Windows 文件系统性能极差。这些不是代码问题,是运行环境前提。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










