轻松监控文件系统变化:Watchdog | python小知识

在开发和运维过程中,监控文件系统以检测文件的变化是一项常见需求。Python的Watchdog库为开发者提供了一个强大而简单的工具来实现这一功能。无论是自动备份、日志监控,还是开发工具的热重载,Watchdog都能帮助我们轻松实现。

1. 安装 Watchdog

在开始之前,确保你的环境中安装了Watchdog库。你可以通过以下命令安装:

pip install watchdog

2. 基本用法

Watchdog的核心组件是Observer类和事件处理器FileSystemEventHandler。让我们从一个简单的例子开始:

示例 1:监控文件的修改
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

# 创建一个事件处理器类,继承自FileSystemEventHandler
class SimpleHandler(FileSystemEventHandler):
    def on_modified(self, event):
        if not event.is_directory:
            print(f"文件被修改: {event.src_path}")

# 主程序
if __name__ == "__main__":
    path = "."  # 监控当前目录
    event_handler = SimpleHandler()
    observer = Observer()
    observer.schedule(event_handler, path, recursive=False)
    observer.start()

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()
代码说明:
  1. 导入模块:导入必要的模块,包括时间模块timewatchdog.observers中的Observerwatchdog.events中的FileSystemEventHandler
  2. 定义事件处理器:创建一个SimpleHandler类,继承自FileSystemEventHandler。在on_modified方法中,判断事件不是目录,并打印出被修改文件的路径。
  3. 设置监控路径:设置path为当前目录"."
  4. 初始化观察者:创建Observer对象,并使用observer.schedule()方法将事件处理器与路径绑定。
  5. 启动观察者:调用observer.start()启动监控。
  6. 保持运行:使用while True循环保持脚本运行,并通过try-except块捕捉键盘中断以停止观察者。

3. 应用场景 1:自动备份

在文件被创建或修改时,将其自动复制到备份目录。

import os
import shutil
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

class BackupHandler(FileSystemEventHandler):
    def __init__(self, dest_dir):
        self.dest_dir = dest_dir
    
    def on_modified(self, event):
        if not event.is_directory:
            self.backup_file(event.src_path)

    def on_created(self, event):
        if not event.is_directory:
            self.backup_file(event.src_path)
    
    def backup_file(self, src_path):
        dest_path = os.path.join(self.dest_dir, os.path.basename(src_path))
        shutil.copy2(src_path, dest_path)
        print(f"文件已备份: {src_path} -> {dest_path}")

if __name__ == "__main__":
    source_dir = "./source"
    dest_dir = "./backup"

    if not os.path.exists(dest_dir):
        os.makedirs(dest_dir)

    event_handler = BackupHandler(dest_dir)
    observer = Observer()
    observer.schedule(event_handler, source_dir, recursive=False)
    observer.start()

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()
代码说明:
  1. BackupHandler:继承自FileSystemEventHandler,实现on_modifiedon_created方法,用于监控文件的创建和修改。
  2. backup_file方法:复制文件到备份目录。
  3. 路径设置:定义source_dir为监控目录,dest_dir为备份目录。如果备份目录不存在,则创建它。
  4. 初始化和启动观察者:同基本用法类似。

4. 应用场景 2:日志监控

监控日志文件的变化,并在发现特定关键词时发出警告。

import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

class LogMonitor(FileSystemEventHandler):
    def __init__(self, log_file, keywords):
        self.log_file = log_file
        self.keywords = keywords
        self.last_position = 0

    def on_modified(self, event):
        if event.src_path == self.log_file:
            with open(self.log_file, 'r') as file:
                file.seek(self.last_position)
                new_content = file.read()
                self.last_position = file.tell()

            for line in new_content.splitlines():
                if any(keyword in line for keyword in self.keywords):
                    print(f"警告: 发现关键词 - {line}")

if __name__ == "__main__":
    log_file = "./app.log"
    keywords = ["ERROR", "CRITICAL", "FATAL"]

    event_handler = LogMonitor(log_file, keywords)
    observer = Observer()
    observer.schedule(event_handler, path='.', recursive=False)
    observer.start()

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()
代码说明:
  1. LogMonitor:继承自FileSystemEventHandler,监控特定日志文件。
  2. on_modified方法:在文件被修改时读取新内容,检查是否包含关键词。
  3. 关键词设置:定义需要监控的关键词,如“ERROR”、“CRITICAL”等。
  4. 初始化观察者:与基本用法一致,但这里只监控特定日志文件。

5. 应用场景 3:开发工具的热重载

监控源代码文件的变化,自动重新加载模块。

import importlib
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

# 假设这是我们要监控的模块
import my_module

class ReloadHandler(FileSystemEventHandler):
    def on_modified(self, event):
        if event.src_path.endswith('.py'):
            print(f"检测到文件变化: {event.src_path}")
            module_name = event.src_path[:-3].replace('/', '.').replace('\\', '.')
            try:
                module = importlib.import_module(module_name)
                importlib.reload(module)
                print(f"模块 {module_name} 已重新加载")
            except ImportError:
                print(f"无法重新加载模块 {module_name}")

if __name__ == "__main__":
    path = "."  # 监控当前目录
    event_handler = ReloadHandler()
    observer = Observer()
    observer.schedule(event_handler, path, recursive=True)
    observer.start()

    try:
        while True:
            # 这里可以调用 my_module 中的函数
            my_module.some_function()
            time.sleep(5)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()
代码说明:
  1. ReloadHandler:继承自FileSystemEventHandler,检测.py文件的修改。
  2. importlib模块:用于动态加载和重新加载模块。
  3. 路径设置:监控当前目录及其子目录中的所有Python文件。

6. 结论

Watchdog库为Python开发者提供了一个强大而简洁的工具,用于监控文件系统的变化。通过上述示例,我们可以看到它在自动备份、日志监控和开发工具热重载等场景中的应用。无论是简单的文件变化检测,还是复杂的自动化工作流,Watchdog都能够胜任。

希望这篇博客能帮助您掌握Watchdog的基本用法,并能在您的项目中发挥作用。如果您对某个特定示例有进一步的疑问或需求,请随时告诉我!