大家好,欢迎来到 Crossin 的编程教室。
在开发自动化脚本时,我们常遇到这种痛点:每当新数据文件存入文件夹,或者修改了配置文件,都必须手动重新运行脚本才能生效。
这种“手动触发”不仅低效,且极易遗漏。虽然可以用 while True 循环去轮询文件时间戳,但写起来麻烦,运行间隔短了浪费 CPU 资源,长了又响应不及时。
为了优雅地解决这个问题,watchdog 库应运而生。它就像一个时刻站岗的哨兵,一旦文件夹内发生任何风吹草动,都能立刻触发预设的动作。
核心功能
watchdog 的高性能源于它直接调用了操作系统的内核接口(如 Linux 的 inotify、Windows 的 ReadDirectoryChangesW)。在实际代码中,主要由两个组件协同工作:
1. 事件处理器 (Event Handler)
负责定义“做什么”。通过继承 FileSystemEventHandler,你可以重写特定的方法:
on_modified():文件内容或元数据被修改时触发。
on_created():新文件或目录诞生时触发。
on_deleted():文件被删除时触发。
2. 观察者 (Observer)
负责定义“盯着谁”。它在一个独立的线程中运行,负责监听系统信号并将其派发给处理器。
示例演示
为了更直接地展示 watchdog 的功能,我们将创建一个“自动化监控器”,实时追踪目录下文件的创建与修改情况。
1. 环境准备
pip install watchdog
2. 完整代码
你可以将以下内容保存为 monitor.py 并运行:
import timeimport sysfrom watchdog.observers import Observerfrom watchdog.events import FileSystemEventHandler
# 1. 定义事件处理器class MyHandler(FileSystemEventHandler): def on_modified(self, event): if not event.is_directory: print(f"【修改】文件:{event.src_path}")
def on_created(self, event): tag = "文件夹" if event.is_directory else "文件" print(f"【新建】{tag}:{event.src_path}")
# 2. 核心控制逻辑if __name__ == "__main__": path = "." # 监控当前目录 event_handler = MyHandler() observer = Observer()
# recursive=True 表示递归监控子目录 observer.schedule(event_handler, path, recursive=True)
print(f"哨兵已就位,正在监控: {path}") observer.start()
try: while True: time.sleep(1) # 保持主线程存活 except KeyboardInterrupt: observer.stop()
observer.join()
代码说明:
MyHandler 继承了基类。通过 event.is_directory 属性,我们可以轻松区分出变动的是普通文件还是文件夹。
observer.start() 会启动一个后台线程。这意味着监控逻辑不会阻塞你主程序的其他业务逻辑。
recursive=True 是个双刃剑,它能帮你盯着所有子文件夹,但在处理海量小文件的项目(如 node_modules)时需要慎用。
使用 try...except 捕获 KeyboardInterrupt(即 Ctrl+C),确保在程序停止时能正常关闭后台线程。
注意事项
在进阶使用 watchdog 时,有一些细节和优化建议能帮你少走弯路:
某些编辑器(如 VS Code)保存文件时会先创建临时文件再覆盖,这可能导致一次保存触发两次 on_modified。建议在代码中加入时间戳判断,过滤掉连续多次的改动。
不要在事件处理函数里写耗时太长的逻辑(比如上传大文件)。建议使用队列(Queue)将任务传出去,让监控线程尽可能简单。
常用场景
watchdog 主要用于各种可自动触发操作的场景,比如:
开发辅助:代码改动后自动运行单元测试。
办公自动化:监控下载目录,根据文件后缀名自动归档。
安全报警:监控敏感配置文件,防止被恶意篡改。
掌握了 watchdog,你就等于拥有了一套通用的“文件触发工作流”。你可以将这个模块化思路应用到任何需要实时响应的项目中,让你的 Python 脚本“动”起来。
最后留个思考题:如果想在监控到 .log 文件产生时自动把它备份到一个叫做 logs_backup 的目录里,要怎么做?来动手试试看吧。
如果本文对你有帮助,欢迎点赞、评论、转发。你们的支持是我更新的动力~
感谢转发和点赞的各位~