Python中WatchDog的使用經(jīng)驗(yàn)總結(jié)
概述
首先聲明,本文討論的 watchdog,不是單片機(jī)里的 watchdog,也不是 linux 中的 watchdog,而是 python 世界里用來(lái)監(jiān)視文件系統(tǒng)變化的一個(gè)第三方模塊。在 python 中文件監(jiān)視主要有兩個(gè)庫(kù),一個(gè)是 pyinotify,一個(gè)是 watchdog。pyinotify 依賴(lài)于 linux 平臺(tái)的 inotify 機(jī)制,只能應(yīng)用在 linux 平臺(tái)上。watchdog 則對(duì)不同平臺(tái)的的事件都進(jìn)行了封裝,不僅可以監(jiān)視 windows 文件系統(tǒng),也可以監(jiān)視 linux 的文件系統(tǒng)。
文件系統(tǒng)事件類(lèi)
文件系統(tǒng)事件基類(lèi)定義如下:
watchdog.events.FileSystemEvent(event_type, src_path, is_directory=False) # event.event_type - 事件類(lèi)型,為 moved / deleted / created / modified 其中之一 # event.src_path - 觸發(fā)該事件的文件或目錄路徑 # event.is_directory - 該事件是否由一個(gè)目錄觸發(fā)
由 watchdog.events.FileSystemEvent 基類(lèi)派生的子類(lèi)如下:
watchdog.events.FileDeletedEvent() # 文件被刪除時(shí)觸發(fā)該事件 watchdog.events.DirDeletedEvent() # 目錄被刪除時(shí)觸發(fā)該事件 watchdog.events.FileCreatedEvent() # 文件被創(chuàng)建時(shí)觸發(fā)該事件 watchdog.events.DirCreatedEvent() # 目錄被創(chuàng)建時(shí)觸發(fā)該事件 watchdog.events.FileModifiedEvent() # 文件被修改時(shí)觸發(fā)該事件(修改文件內(nèi)容、修改文件inode信息如權(quán)限和訪(fǎng)問(wèn)時(shí)間,都會(huì)觸發(fā)該事件) watchdog.events.DirModifiedEvent() # 目錄被修改時(shí)觸發(fā)該事件 watchdog.events.FileMovedEvent() # 文件被移動(dòng)或重命名時(shí)觸發(fā)該事件,因?yàn)樯婕拔募苿?dòng),所以除了event.src_path表示原路徑,還有event.dest_path表示目的路徑 watchdog.events.DirMovedEvent() # 目錄被移動(dòng)或重命名時(shí)觸發(fā)該事件,因?yàn)樯婕拔募苿?dòng),所以除了event.src_path表示原路徑,還有event.dest_path表示目的路徑
文件系統(tǒng)事件處理類(lèi)
watchdog.events.FileSystemEventHandler 是事件處理器的基類(lèi),用于處理事件,用戶(hù)需繼承該類(lèi),并在子類(lèi)中重寫(xiě)對(duì)應(yīng)方法。需要用戶(hù)重寫(xiě)的方法有:
self.on_any_event(event) # 任何事件發(fā)生都會(huì)首先執(zhí)行該方法,該方法默認(rèn)為空,dispatch()方法會(huì)先執(zhí)行該方法,然后再把 event 分派給其他方法處理 self.on_moved(event) # 處理 DirMovedEvent 和 FileMovedEvent 事件,默認(rèn)為空 self.on_created(event) # 處理 DirCreatedEvent 和 FileCreatedEvent 事件,默認(rèn)為空 self.on_deleted(event) # 處理 DirDeletedEvent 和 FileDeletedEvent 事件,默認(rèn)為空 self.on_modified(event) # 處理 DirModifiedEvent 和 FileModifiedEvent 事件,默認(rèn)為空
以上方法中,event 有幾個(gè)屬性可用:
- event.is_directory - 觸發(fā)事件的是否為文件夾
- event.src_path - 源路徑
- event.dest_path - 目標(biāo)路徑
最簡(jiǎn)單的應(yīng)用示例
下面的例子展示了如何監(jiān)視 D:\XufiveGit\PEC\client 文件夾內(nèi)所有文件的 moved / deleted / created / modified。請(qǐng)注意,重命名被視為 moved (移動(dòng))。
#-*- 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()
存在的問(wèn)題
真正測(cè)試過(guò)之后,你會(huì)發(fā)現(xiàn),上面的例子幾乎沒(méi)有實(shí)用價(jià)值,因?yàn)?,文件操作引發(fā)的事件比我們想象的多了不少,而且難以在事件函數(shù)中做出針對(duì)性處理。比如,添加一個(gè)文件,勢(shì)必引發(fā) created 事件,同時(shí)也會(huì)導(dǎo)致所在文件夾的 modified 事件,如果該文件目錄比較深,還會(huì)引發(fā)多層父級(jí)文件夾的 modified 事件。
如果,你覺(jué)得這不算什么問(wèn)題,那么,在 windows 平臺(tái)上每一次的文件修改引發(fā)兩次 modified 事件,算不算一個(gè)令人頭疼的問(wèn)題呢?在 linux 平臺(tái)上表現(xiàn)如何,我沒(méi)有測(cè)試過(guò),但在 windows 平臺(tái)上,由于 watchdog 封裝的是 windows 系統(tǒng)的 FileSystemWatcher Events,處理文件的過(guò)程中執(zhí)行了多次文件系統(tǒng)操作,無(wú)法避免地觸發(fā)了多次事件。
改進(jìn)方案
如果對(duì)監(jiān)視文件的實(shí)時(shí)性要求不高,又懶得處理一大堆事件,那么,比較事件前后的文件夾快照就是一個(gè)值得嘗試的改進(jìn)方案。實(shí)現(xiàn)這個(gè)思路,有三個(gè)前提條件:
- 快速獲取文件夾快照。幸運(yùn)的是,watchdog 模塊為我們提供了 DirectorySnapshot 功能
- 可以接受200毫秒的延時(shí)。文件操作引發(fā)的一大堆事件會(huì)集中在一個(gè)較短的時(shí)間內(nèi),一般情況下,在文件操作之后200毫秒獲取文件夾快照,是一個(gè)不錯(cuò)的間隔
- 快速比較文件夾快照。這也不是問(wèn)題,watchdog 模塊有 DirectorySnapshotDiff 子模塊
改進(jìn)思路是這樣的:設(shè)置一個(gè)定時(shí)器, 200毫秒后抓取快照,并與上一張快照比較。每當(dāng)有事件發(fā)生時(shí),檢查定時(shí)器是否已經(jīng)啟動(dòng)。如果未啟動(dòng),則直接啟動(dòng)定時(shí)器;否則,說(shuō)明該事件距離上次事件不足200毫秒,可視為是同一組事件,此時(shí)終止定時(shí)器,再次重啟。具體代碼如下:
#-*- 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)
# 接下來(lái)就是你想干的啥就干點(diǎn)啥,或者該干點(diǎn)啥就干點(diǎn)啥
pass
class DirMonitor(object):
"""文件夾監(jiān)視類(lèi)"""
def __init__(self, aim_path):
"""構(gòu)造函數(shù)"""
self.aim_path= aim_path
self.observer = Observer()
def start(self):
"""啟動(dòng)"""
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()
到此這篇關(guān)于Python中WatchDog的使用經(jīng)驗(yàn)總結(jié)的文章就介紹到這了,更多相關(guān)Python WatchDog內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python使用Selenium實(shí)現(xiàn)淘寶搶單的流程分析
這篇文章主要介紹了Python使用Selenium實(shí)現(xiàn)淘寶搶單的流程分析,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
Python隊(duì)列RabbitMQ 使用方法實(shí)例記錄
這篇文章主要介紹了Python隊(duì)列RabbitMQ 使用方法,結(jié)合實(shí)例形式分析了Python隊(duì)列RabbitMQ創(chuàng)建隊(duì)列發(fā)送消息與創(chuàng)建消費(fèi)者消費(fèi)信息相關(guān)操作技巧,需要的朋友可以參考下2019-08-08
python如何實(shí)現(xiàn)全角半角的相互轉(zhuǎn)換
這篇文章主要介紹了python如何實(shí)現(xiàn)全角半角的相互轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
python3實(shí)現(xiàn)隨機(jī)數(shù)
這篇文章主要為大家詳細(xì)介紹了python3實(shí)現(xiàn)隨機(jī)數(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06
python pygame實(shí)現(xiàn)方向鍵控制小球
這篇文章主要為大家詳細(xì)介紹了python pygame實(shí)現(xiàn)方向鍵控制小球,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05
使用Python判斷質(zhì)數(shù)(素?cái)?shù))的簡(jiǎn)單方法講解
這篇文章主要介紹了使用Python判斷質(zhì)數(shù)(素?cái)?shù))的簡(jiǎn)單方法講解,經(jīng)常被用來(lái)做科學(xué)計(jì)算的Python處理這種小問(wèn)題當(dāng)然手到擒來(lái)^_-需要的朋友可以參考下2016-05-05
Python Web框架Pylons中使用MongoDB的例子
這篇文章主要介紹了Python Web框架Pylons中使用MongoDB 的例子,大家參考使用2013-12-12

