Python中WatchDog的使用经验总结

 更新时间:2023年12月19日 09:07:32   作者:天元浪子  
在 python 中文件监视主要有两个库,一个是 pyinotify,一个是 watchdog,本文主要为大家详细介绍一下Python中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:\XufiveGit\PEC\client 文件夹内所有文件的 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:\XufiveGit\PEC\client", 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:\XufiveGit\PEC\client")
    monitor.start()

到此这篇关于Python中WatchDog的使用经验总结的文章就介绍到这了,更多相关Python WatchDog内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • centos6.7安装python2.7.11的具体方法

    centos6.7安装python2.7.11的具体方法

    下面小编就为大家带来一篇centos6.7安装python2.7.11的具体方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • Python数据处理篇之Sympy系列(五)---解方程

    Python数据处理篇之Sympy系列(五)---解方程

    这篇文章主要介绍了Python数据处理篇之Sympy系列(五)---解方程,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-10-10
  • Python+turtle绘制七夕表白玫瑰花

    Python+turtle绘制七夕表白玫瑰花

    七夕节,又称“七巧节”“女儿节”“乞巧节”等,是中国民间的传统节日。一年一度的七夕又快到了,用Python画一朵玫瑰花送给你的那个TA吧
    2022-08-08
  • 在Django的视图中使用数据库查询的方法

    在Django的视图中使用数据库查询的方法

    这篇文章主要介绍了在Django的视图中使用数据库查询的方法,是Python的Django框架使用的基础操作,需要的朋友可以参考下
    2015-07-07
  • Python中集合类型(set)学习小结

    Python中集合类型(set)学习小结

    这篇文章主要介绍了Python中集合类型(set)学习小结,本文讲解了set的初始化、运算操作、基本方法等内容,需要的朋友可以参考下
    2015-01-01
  • Python GUI库Tkiner使用方法代码示例

    Python GUI库Tkiner使用方法代码示例

    这篇文章主要介绍了Python GUI库Tkiner使用方法代码示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • PyTorch、torchvision和Python版本的对应关系

    PyTorch、torchvision和Python版本的对应关系

    使用PyTorch时,选择合适的Python版本是至关重要的,错误的版本组合可能导致各种兼容性问题,本文就来介绍一下PyTorch、torchvision与Python版本匹配,感兴趣的可以了解一下
    2024-03-03
  • Python破解网站登录密码脚本

    Python破解网站登录密码脚本

    这篇文章主要为大家介绍一个简单的Python暴力破解网站登录密码脚本,文中的过程讲解详细,对我们学习Python有一定的帮助,感兴趣的可以学习一下
    2022-01-01
  • python目标检测实现黑花屏分类任务示例

    python目标检测实现黑花屏分类任务示例

    这篇文章主要为大家介绍了python目标检测实现黑花屏分类任务示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • python中f字符串以及其常见用法总结

    python中f字符串以及其常见用法总结

    python中的f是format函数的缩写,用于格式化输出,下面这篇文章主要给大家介绍了关于python中f字符串以及其常见用法的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-05-05

最新评论