• watchdog 监控文件变化使用总结


    概述

    首先声明,本文讨论的 watchdog,不是单片机里的 watchdog,也不是 linux 中的 watchdog,而是 python 世界里用来监视文件系统变化的一个第三方模块。在 python 中文件监视主要有两个库,一个是 pyinotify,一个是 watchdog。pyinotify 依赖于 linux 平台的 inotify 机制,只能应用在 linux 平台上。watchdog 则对不同平台的的事件都进行了封装,不仅可以监视 windows 文件系统,也可以监视 linux 的文件系统。

    文件系统事件类

    文件系统事件基类定义如下:

       watchdog.events.FileSystemEvent(event_type, src_path, is_directory=False)
      # event.event_type - 事件类型,为 moved / deleted / created / modified 其中之一
      # event.src_path - 触发该事件的文件或目录路径
      # event.is_directory - 该事件是否由一个目录触发

    由 watchdog.events.FileSystemEvent 基类派生的子类如下:

       watchdog.events.FileDeletedEvent() 

      # 文件被删除时触发该事件

      watchdog.events.DirDeletedEvent()
      # 目录被删除时触发该事件

      watchdog.events.FileCreatedEvent()
      # 文件被创建时触发该事件

      watchdog.events.DirCreatedEvent()
      # 目录被创建时触发该事件

      watchdog.events.FileModifiedEvent()
      # 文件被修改时触发该事件(修改文件内容、修改文件inode信息如权限和访问时间,都会触发该事件)

      watchdog.events.DirModifiedEvent()
      # 目录被修改时触发该事件

      watchdog.events.FileMovedEvent()
      # 文件被移动或重命名时触发该事件,因为涉及文件移动,所以除了event.src_path表示原路径,还有event.dest_path表示目的路径

      watchdog.events.DirMovedEvent()
      # 目录被移动或重命名时触发该事件,因为涉及文件移动,所以除了event.src_path表示原路径,还有event.dest_path表示目的路径

     文件系统事件处理类

     watchdog.events.FileSystemEventHandler 是事件处理器的基类,用于处理事件,用户需继承该类,并在子类中重写对应方法。需要用户重写的方法有:

        self.on_any_event(event)
      # 任何事件发生都会首先执行该方法,该方法默认为空,dispatch()方法会先执行该方法,然后再把 event 分派给其他方法处理

      self.on_moved(event)
      # 处理 DirMovedEvent 和 FileMovedEvent 事件,默认为空

      self.on_created(event)
      # 处理 DirCreatedEvent 和 FileCreatedEvent 事件,默认为空

      self.on_deleted(event)
      # 处理 DirDeletedEvent 和 FileDeletedEvent 事件,默认为空

      self.on_modified(event)
      # 处理 DirModifiedEvent 和 FileModifiedEvent 事件,默认为空

    以上方法中,event 有几个属性可用:

    • event.is_directory - 触发事件的是否为文件夹
    • event.src_path - 源路径
    • event.dest_path - 目标路径
    最简单的应用示例

    下面的例子展示了如何监视 D:XufiveGitPECclient 文件夹内所有文件的 moved / deleted / created / modified。请注意,重命名被视为 moved (移动)。

    #-*- coding: utf-8 -*-
    
    from watchdog.observers import Observer
    from watchdog.events import *
    
    class FileEventHandler(FileSystemEventHandler):
      def on_any_event(self, event):
        pass
    
      def on_moved(self, event):
        if event.is_directory:
          print("directory moved from {0} to {1}".format(event.src_path,event.dest_path))
        else:
          print("file moved from {0} to {1}".format(event.src_path,event.dest_path))
    
      def on_created(self, event):
        if event.is_directory:
          print("directory created:{0}".format(event.src_path))
        else:
          print("file created:{0}".format(event.src_path))
    
      def on_deleted(self, event):
        if event.is_directory:
          print("directory deleted:{0}".format(event.src_path))
        else:
          print("file deleted:{0}".format(event.src_path))
    
      def on_modified(self, event):
        if event.is_directory:
          print("directory modified:{0}".format(event.src_path))
        else:
          print("file modified:{0}".format(event.src_path))
    
    if __name__ == "__main__":
      import time
      observer = Observer()
      event_handler = FileEventHandler()
      observer.schedule(event_handler, r"D:XufiveGitPECclient", True)  # 执行模块,是否递归监控       
      observer.start()
      try:
        while True:
          time.sleep(1)
    
      except KeyboardInterrupt:
        observer.stop()
    存在的问题
    真正测试过之后,你会发现,上面的例子几乎没有实用价值,因为,文件操作引发的事件比我们想象的多了不少,而且难以在事件函数中做出针对性处理。
    比如,添加一个文件,势必引发 created 事件,同时也会导致所在文件夹的 modified 事件,如果该文件目录比较深,还会引发多层父级文件夹的 modified 事件。 如果,你觉得这不算什么问题,那么,在 windows 平台上每一次的文件修改引发两次 modified 事件,算不算一个令人头疼的问题呢?
    在 linux 平台上表现如何,我没有测试过,但在 windows 平台上,由于 watchdog 封装的是 windows 系统的 FileSystemWatcher Events,
    处理文件的过程中执行了多次文件系统操作,无法避免地触发了多次事件。

    改进方案

    如果对监视文件的实时性要求不高,又懒得处理一大堆事件,那么,比较事件前后的文件夹快照就是一个值得尝试的改进方案。实现这个思路,有三个前提条件:
    
    快速获取文件夹快照。幸运的是,watchdog 模块为我们提供了 DirectorySnapshot 功能
    可以接受200毫秒的延时。文件操作引发的一大堆事件会集中在一个较短的时间内,一般情况下,在文件操作之后200毫秒获取文件夹快照,是一个不错的间隔
    快速比较文件夹快照。这也不是问题,watchdog 模块有 DirectorySnapshotDiff 子模块

    改进思路是这样的:设置一个定时器, 200毫秒后抓取快照,并与上一张快照比较。每当有事件发生时,检查定时器是否已经启动。如果未启动,则直接启动定时器;否则,说明该事件距离上次事件不足200毫秒,可视为是同一组事件,此时终止定时器,再次重启。具体代码如下:

    #-*- coding: utf-8 -*-
    
    import os, threading
    from watchdog.observers import Observer
    from watchdog.events import *
    from watchdog.utils.dirsnapshot import DirectorySnapshot, DirectorySnapshotDiff
    
    class FileEventHandler(FileSystemEventHandler):
      def __init__(self, aim_path):
        FileSystemEventHandler.__init__(self)
        self.aim_path = aim_path
        self.timer = None
        self.snapshot = DirectorySnapshot(self.core.proj_path)
    
      def on_any_event(self, event):
        if self.timer:
          self.timer.cancel()
        self.timer = threading.Timer(0.2, self.checkSnapshot)
        self.timer.start()
    
      def checkSnapshot(self):
        snapshot = DirectorySnapshot(self.aim_path)
        diff = DirectorySnapshotDiff(self.snapshot, snapshot)
        self.snapshot = snapshot
        self.timer = None
        #下面是应处理的各种事项
        print("files_created:", diff.files_created)
        print("files_deleted:", diff.files_deleted)
        print("files_modified:", diff.files_modified)
        print("files_moved:", diff.files_moved)
        print("dirs_modified:", diff.dirs_modified)
        print("dirs_moved:", diff.dirs_moved)
        print("dirs_deleted:", diff.dirs_deleted)
        print("dirs_created:", diff.dirs_created)
        # 接下来就是你想干的啥就干点啥,或者该干点啥就干点啥
        pass
    
    class DirMonitor(object):
      """文件夹监视类"""
    
      def __init__(self, aim_path):
        """构造函数"""
        self.aim_path= aim_path
        self.observer = Observer()
    
      def start(self):
        """启动"""
        event_handler = FileEventHandler(self.aim_path)
        self.observer.schedule(event_handler, self.aim_path, True)
        self.observer.start()
    
      def stop(self):
        """停止"""
        self.observer.stop()
    
    if __name__ == "__main__":
    monitor = DirMonitor(r"D:XufiveGitPECclient")
    monitor.start()
  • 相关阅读:
    Recommended Books for Algo Trading in 2020
    Market Making is simpler than you think!
    Top Crypto Market Makers of 2020
    Top Crypto Market Makers, Rated and Reviewed
    爬取伯乐在线文章(五)itemloader
    爬取伯乐在线文章(四)将爬取结果保存到MySQL
    爬取伯乐在线文章(三)爬取所有页面的文章
    爬取伯乐在线文章(二)通过xpath提取源文件中需要的内容
    爬取伯乐在线文章(一)
    爬虫去重策略
  • 原文地址:https://www.cnblogs.com/luochunxi/p/14113351.html
Copyright © 2020-2023  润新知