Python神器之使用watchdog監(jiān)控文件變化
一、官方文檔
需要細(xì)節(jié)選擇去官網(wǎng),需要了解和應(yīng)用范例看本文即可
https://pythonhosted.org/watchdog/官網(wǎng)上的:User’s Guide,主要看API相關(guān)這里即可
- 安裝
- 快速開(kāi)始
- API 相關(guān)
二、watchdog安裝
watchdog需要在python2.6以上的版本工作,如果使用的是Linux//FreeBSD/Mac OS X 系統(tǒng),python已經(jīng)安裝了,但是需要保證python的版本至少是python2.7(學(xué)習(xí)用最好還是使用3.6以上的版本吧)
下面有三種不同的安裝方法:選擇第一種最簡(jiǎn)單的就行了,可以簡(jiǎn)便的不要自求麻煩。
1. Installing from PyPI using pip
pip install watchdog
2. Installing from source tarballs
$ wget -c http://pypi.python.org/packages/source/w/watchdog/watchdog-0.8.2.tar.gz $ tar zxvf watchdog-0.8.2.tar.gz $ cd watchdog-0.8.2 $ python setup.py install
3. Installing from the code repository
$ git clone --recursive git://github.com/gorakhargosh/watchdog.git $ cd watchdog $ python setup.py install
在官方還說(shuō)需要下載一些依賴,但是你使用第一種pip安裝的方法基本都不會(huì)有這種需求。
三、快速開(kāi)始(官方范例)
下面我們提供一個(gè)簡(jiǎn)單的示例,該示例以遞歸方式監(jiān)視當(dāng)前目錄(這意味著它將遍歷所有子目錄)以檢測(cè)更改。 這是我們將要使用的API:
1.創(chuàng)建watchdog.observers.Observer線程類的實(shí)例
2.實(shí)現(xiàn)watchdog.events.FileSystemEventHandler的子類(或者在我們的例子中,我們將使用內(nèi)置的watchdog.events.LoggingEventHandler)。
3.通過(guò)附加事件處理程序的觀察者實(shí)例來(lái)計(jì)劃監(jiān)視一些路徑。
4.啟動(dòng)觀察者線程并等待它生成事件而不會(huì)阻塞我們的主線程。
import sys
import time
import logging
from watchdog.observers import Observer # 監(jiān)控
from watchdog.events import LoggingEventHandler # 觸發(fā)事件
?
if __name__=='__main__':
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
path = sys.argv[1] if len(sys.argv) > 1 else '.'
event_handler = LoggingEventHandler() # 監(jiān)控處理事件的方法,這個(gè)類非常重要,可以根據(jù)自己的需要重寫
observer = Observer() # 定義監(jiān)控類,多線程類 thread class
observer.schedule(event_handler,'./monitor_folder_1', recursive=True) # 指定監(jiān)控路徑/觸發(fā)對(duì)應(yīng)的監(jiān)控事件類
observer.start()# 將observer運(yùn)行在同一個(gè)線程之內(nèi),不阻塞主進(jìn)程運(yùn)行,可以調(diào)度observer來(lái)停止該線程
try:
while True:
time.sleep(1) # 監(jiān)控頻率(1s1次,根據(jù)自己的需求進(jìn)行監(jiān)控)
except KeyboardInterrupt:
observer.stop()
observer.join()四、API Reference(翻譯官網(wǎng))
觀察者模型主要有三個(gè)角色:observer、event_handler、被監(jiān)控的文件夾。三者原本是獨(dú)立的,主要通過(guò)observer.schedule函數(shù)將三者串起來(lái),意思為observer不斷檢測(cè)調(diào)用平臺(tái)依賴代碼對(duì)監(jiān)控文件夾進(jìn)行變動(dòng)檢測(cè),當(dāng)發(fā)現(xiàn)改變時(shí),通知event_handler處理。
watchdog.event
模型:watchdog.events簡(jiǎn)介:文件系統(tǒng)事件和時(shí)間處理的程序原作者: yesudeep@google.com (Yesudeep Mangalapilly)
1. Event Class
首先考慮一下關(guān)于文件和文件夾的相關(guān)操作有那些?無(wú)外乎:
- 創(chuàng)建(FileCreatedEvent/DirCreateEvent)
- 移動(dòng)(FileMovedEvent/DirMovedEvent)
- 刪除(FildDeletedEvent/DirDeletedEvent)
- 修改(FileModifiedEvent/DirModifiedEvent)
對(duì)文件/文件夾的監(jiān)控也就無(wú)非以上的操作了,watchdog對(duì)文件夾的監(jiān)控也就是針對(duì)上述需求進(jìn)行設(shè)計(jì)的Event Classes也就包含了大概八個(gè)類(都分別依賴于watchdog.events.FileSystemEvent 和watchdog.events.FileSystemMovedEvent):
- class watchdog.events.FileMovedEvent(src_path, dest_path)
- class watchdog.events.DirMovedEvent(src_path, dest_path)
- class watchdog.events.FileModifiedEvent(src_path)
- class watchdog.events.DirModifiedEvent(src_path)
- class watchdog.events.FileCreatedEvent(src_path)
- class watchdog.events.DirCreatedEvent(src_path)
- class watchdog.events.FileDeletedEvent(src_path)
- class watchdog.events.DirDeletedEvent(src_path)
2. Event handler Classes事件處理類
官方文件中對(duì)Event Handler Classes的說(shuō)明:
class watchdog.events.FileSystemEventHandler[source]
Bases: object
Base file system event handler that you can override methods from.
dispatch(event)[source]
Dispatches events to the appropriate methods.
Parameters:event (FileSystemEvent) – The event object representing the file system event.
on_any_event(event)[source]
Catch-all event handler.
Parameters:event (FileSystemEvent) – The event object representing the file system event.
on_created(event)[source]
Called when a file or directory is created.
Parameters:event (DirCreatedEvent or FileCreatedEvent) – Event representing file/directory creation.
on_deleted(event)[source]
Called when a file or directory is deleted.
Parameters:event (DirDeletedEvent or FileDeletedEvent) – Event representing file/directory deletion.
on_modified(event)[source]
Called when a file or directory is modified.
Parameters:event (DirModifiedEvent or FileModifiedEvent) – Event representing file/directory modification.
on_moved(event)[source]
Called when a file or a directory is moved or renamed.
Parameters:event (DirMovedEvent or FileMovedEvent) – Event representing file/directory movement.
上述也就說(shuō)明了watchdog的觸發(fā)事件的方法為:
- dispatch
- on_any_event
- on_create
- on_delete
- on_modified
- on_moved
3. watchdog.observers.api
class watchdog.observers.api.ObservedWatch(path, recursive)
Bases: object
An scheduled watch.
Parameters:
path – Path string.
recursive:
True if watch is recursive;
False
otherwise.is_recursive:Determines whether subdirectories are watched for the path.
path:The path that this watch monitors
Observer用以監(jiān)控文件的變化,根據(jù)觸發(fā)事件調(diào)用相關(guān)聯(lián)的事件處理方法來(lái)執(zhí)行。
observer是threading.Thread的子類,通過(guò)observer.start()使之運(yùn)行在一個(gè)線程之中,不阻塞主線程的運(yùn)行,然后可以調(diào)用observer.stop()來(lái)停止該進(jìn)程.
observer.schedule(event_handler,path,recursive=False) # event_handler:觸發(fā)事件的操作方法 # path:監(jiān)控的文件或者目錄 # recursive:如果監(jiān)控的是文件則需要設(shè)置為True
五、linux中使用watchdog監(jiān)控文件夾各種操作會(huì)觸發(fā)的監(jiān)控事件
1. 移除文件
文件刪除:File_deleted
文件夾修改 Directory_modified
2. 添加文件
文件新建:File_created
文件夾修改:Directory_modified
3.修改文件
兩次文件修改:File_modified(顯示針對(duì)一個(gè)備份文件,然后是針對(duì)原始文件)
刪除備份文件:File_deleted
文件夾修改:Directory_modified
4.文件改名
文件移動(dòng):File_moved
文件夾修改:Directory_modified
5.使用cp命令復(fù)制文件到監(jiān)控目錄
文件新建:File_created
一大堆文件修改操作:Directory_modified
文件夾修改操作:File_modified
六、應(yīng)用實(shí)例
1.監(jiān)控文件夾中是否有后綴為".segy"的文件進(jìn)入
#! /home/liufeng/project
# -*- coding:utf-8 -*-
# Created by jerry_liufeng
?
# 本模塊的功能:<檢測(cè)文件夾變化>
?
# 導(dǎo)入watchdog對(duì)應(yīng)模塊
from watchdog.observers import Observer
from watchdog.events import *
# 導(dǎo)入時(shí)間模塊
import time
?
class FileEventHandler(FileSystemEventHandler):
# 初始化魔術(shù)方法
def __init__(self):
FileSystemEventHandler.__init__(self)
self.fileNameList = [] # 文件名列表(存儲(chǔ)文件名)
?
# 文件或文件夾移動(dòng)
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))
?
# 創(chuàng)建文件或文件夾
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))
fileAllName =str(event.src_path.split('/')[-1])
if fileAllName.endswith('.segy'):
self.fileNameList.append(fileAllName)
print(self.fileNameList)
# 刪除文件或文件夾
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__":
# 實(shí)例化Observer對(duì)象
observer = Observer()
event_handler = FileEventHandler()
# 設(shè)置監(jiān)聽(tīng)目錄
dis_dir = "./03_seis_data/"
observer.schedule(event_handler,dis_dir,True)
observer.start()
try:
while True:
# 設(shè)置監(jiān)聽(tīng)頻率(間隔周期時(shí)間)
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()說(shuō)明:之所以注釋掉modified這段代碼是因?yàn)槲谊P(guān)心的是文件的進(jìn)入,而非文件內(nèi)容的改變,太過(guò)頻繁的modified操作會(huì)影響我對(duì)新增文件數(shù)量的判斷。
2.監(jiān)控多個(gè)文件夾
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import time
?
class FileEventHandler(FileSystemEventHandler):
def __init__(self):
FileSystemEventHandler.__init__(self)
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__":
observer = Observer()
dirs = [r'./monitor_folder_1', r'./monitor_folder_1']
# dirs = [ r'./monitor_folder_1']
for dir in dirs:
event_handler = FileEventHandler()
observer.schedule(event_handler, dir, True)
observer.start()3.文件系統(tǒng)一次操作多次觸發(fā)各類事件問(wèn)題解決
原文參考:Python中WatchDog的使用經(jīng)驗(yàn)總結(jié)
問(wèn)題:
文件操作引發(fā)的事件比我們想象的多了不少,而且難以在事件函數(shù)中做出針對(duì)性處理。
在 windows 平臺(tái)上每一次的文件修改引發(fā)兩次 modified 事件?在 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í)器,再次重啟。具體代碼如下:
import time
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.aim_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)
# 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))
?
?
class DirMonitor(object):
"""文件夾監(jiān)視類"""
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"./monitor_folder_1")
monitor.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
monitor.stop()以上就是Python神器之使用watchdog監(jiān)控文件變化的詳細(xì)內(nèi)容,更多關(guān)于Python watchdog監(jiān)控文件變化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用PyTorch訓(xùn)練一個(gè)圖像分類器實(shí)例
今天小編就為大家分享一篇使用PyTorch訓(xùn)練一個(gè)圖像分類器實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01
python工具快速為音視頻自動(dòng)生成字幕(使用說(shuō)明)
這篇文章主要介紹了python工具快速為音視頻自動(dòng)生成字幕(使用說(shuō)明),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
Python字符串的創(chuàng)建和駐留機(jī)制詳解
字符串駐留是一種在內(nèi)存中僅保存一份相同且不可變字符串的方法,本文重點(diǎn)給大家介紹Python字符串的創(chuàng)建和駐留機(jī)制,感興趣的朋友跟隨小編一起看看吧2022-02-02
Python整數(shù)對(duì)象實(shí)現(xiàn)原理詳解
這篇文章主要介紹了Python整數(shù)對(duì)象實(shí)現(xiàn)原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
pyecharts在數(shù)據(jù)可視化中的應(yīng)用詳解
這篇文章主要介紹了pyecharts在數(shù)據(jù)可視化中的應(yīng)用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
Python 使用 raise 語(yǔ)句拋出異常的流程分析
在Python編程中,異常處理是至關(guān)重要的一部分,本文將探討 Python 中 raise 語(yǔ)句的使用方法以及如何通過(guò) raise 語(yǔ)句來(lái)拋出各種類型的異常,從而有效地進(jìn)行異常處理,感興趣的朋友跟隨小編一起看看吧2021-02-02
用Python編寫個(gè)解釋器實(shí)現(xiàn)方法接受
計(jì)算機(jī)只能理解機(jī)器碼。歸根結(jié)底,編程語(yǔ)言只是一串文字,目的是為了讓人類更容易編寫他們想讓計(jì)算機(jī)做的事情。真正的魔法是由編譯器和解釋器完成,它們彌合了兩者之間的差距。解釋器逐行讀取代碼并將其轉(zhuǎn)換為機(jī)器碼2023-01-01

