watchdog 是监听文件夹新建事件最稳方案,它跨平台封装系统级 api 精准捕获 created 事件;需重写 on_created、过滤非目录、禁用递归;ftp 上传须用 ftplib 而非 requests;上传前校验文件大小防截断;必须捕获 ftplib 异常并记录日志。

用 watchdog 监听文件夹新建事件最稳
Python 原生没有跨平台的实时文件监听能力,os.listdir() 轮询既耗资源又容易漏事件。watchdog 是目前最成熟的选择,它封装了 Linux 的 inotify、macOS 的 FSEvents、Windows 的 ReadDirectoryChangesW,能精准捕获 Created 事件,且不依赖轮询。
安装:pip install watchdog
关键点:
- 监听必须用
FileSystemEventHandler子类重写on_created方法,不是on_modified—— 新建文件时,系统先触发Created,再可能触发Modified(比如写入未完成),但上传只需响应前者 - 务必检查
event.is_directory == False,否则新建子文件夹也会触发上传逻辑 -
observer.schedule()的第三个参数设为recursive=False,除非你明确要监听所有子目录
FTP 上传要用 ftplib.FTP 而非 requests
requests 不能上传文件到 FTP,它只支持 HTTP/HTTPS。FTP 协议和传输机制完全不同,强行套用会直接报 ConnectionRefusedError 或 Unknown URL type: 'ftp'。
正确做法是用标准库 ftplib:
- 连接后立即调用
ftp.login(),否则后续操作全失败 - 上传前用
ftp.cwd()切到目标目录,不要指望路径拼在storbinary()参数里自动创建 —— 它不递归建目录 - 二进制模式上传:用
ftp.storbinary(f"STOR {filename}", open(filepath, "rb")),文本模式会破坏图片、PDF 等非文本文件 - 注意
ftp.quit()必须放在finally块里,否则异常中断会导致连接堆积
on_created 触发时文件可能还没写完
操作系统通知“文件已创建”不等于“内容已落盘”。尤其大文件或 NFS 挂载目录下,open(filepath, "rb") 可能读到空内容或截断数据,上传后远端文件损坏。
稳妥做法是加轻量级等待和校验:
- 用
os.path.getsize(filepath)检查是否 > 0,否则time.sleep(0.1)后重试,最多 3 次 - 避免用
time.sleep(1)这种固定延时 —— 小文件等太久,大文件又可能不够 - 如果业务允许,可改用
on_closed_write(需用inotify底层,watchdog不直接暴露,得换inotify-simple)
生产环境必须处理连接失败和重试
FTP 服务器宕机、网络抖动、权限变更都会让上传失败,但 watchdog 不会因此停止监听 —— 错误若没捕获,整个监控进程就崩了。
必须包裹上传逻辑:
- 对
ftplib.all_errors(包含error_perm、error_temp、error_proto等)做统一捕获 - 失败后记录日志(至少含
filepath和str(e)),别只 print - 单次失败不重试(防止雪崩),但可把失败文件路径记入本地队列,另起线程定时重传
- FTP 登录超时默认 30 秒,太长,建议显式设
FTP(timeout=10)
路径、权限、网络状态这三块出问题的概率远高于逻辑本身,监控脚本跑得越久,越要盯住这些地方。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











