仕事でPythonを使ったミニプログラムを作ることになって、その要件の中にフォルダ監視があったので、調べてみました。
この手の情報はWeb上にたくさんありますが、どれも説明やサンプルが長くて、読むのが大変だったので、端的にまとめてみました。
やりたいことは、「指定したフォルダ内の変化を捉えたい」ということなので、一番シンプルで応用が利く書き方を紹介します。
watchdog ライブラリの簡単な使い方
Pythonでフォルダ監視をする場合、watchdoc ライブラリを使います。
次の通り4つのステップで実現可能です。
下記が具体的なサンプルプログラムになります。このままコピペして、 on_any_event メソッドの部分と、path=~の部分を書き換えれば、そのまま使えます。
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import time
#ファイル/フォルダの変化があった時に呼ばれるイベントハンドラ
class EventHandler(FileSystemEventHandler):
def on_any_event(self,e):
print(f"{e.is_directory} : {e.event_type} : {e.src_path}")
#ファイル/フォルダの監視を開始
observer = Observer()
observer.schedule(EventHandler(), path='p:/', recursive=True)
observer.start()
#監視のためのループ処理
while True:
time.sleep(1)
scheduleメソッドの第一引数には、ファイルやフォルダに変化があった際に呼び出されるイベントハンドラのインスタンスを指定します。
次に、path 引数に、監視対象となるフォルダのパスを指定します。
そして、監視対象フォルダ配下のサブフォルダまで再帰的に監視したい場合は recursive=True を指定します。
イベントハンドラの書き方
イベントハンドラ用にFileSystemEventHandlerというクラスが用意されているので、これを継承して独自のイベントハンドラを作成します。
さきほどのサンプルでは、EventHandlerという名前でクラスを作り、FileSystemEventHandlerを継承するようにしました。
そして、イベントハンドラの中に、on_any_event という固定のメソッド名を書きます。
watchdoc は、監視対象フォルダの配下のフォルダやファイルにあらゆる変化が起きた時、on_any_event メソッドを呼び出す仕様になっているため、ここに行いたい処理を記述します。
また、an_any_event を呼び出し時に渡される引数(サンプルでは e) のプロパティを参照することで、何に対してどのような変化が起きたのかを知ることが出来ます。
プロパティ名 | 内容 |
---|---|
is_directory | 変化が起きた対象がディレクトリの場合はTrue、ファイルの場合はFalse |
event_type | 変化の内容が文字列として渡される "modified" →変更 "created" →作成 "deleted" →削除 "moved" →移動 |
src_path | 変化が起きたフォルダまたはファイルのパス |
監視結果のサンプル
先ほどのサンプルプログラムのイベントハンドラ内で、以下のprint文を記述していました。
print(f"{e.is_directory} : {e.event_type} : {e.src_path}")
実際にプログラムを動かして監視対象フォルダに対してファイルやフォルダの更新と削除を行った結果を参考情報として掲載しておきます。
使いやすくクラス化したサンプル
watchdogライブラリ を使ったファイル/フォルダ監視は4ステップで実現できること、クラス化することでコード量が増えることから、ことさらクラス化する必要は無いかもしれません。
しかし、中身を知らずとも簡単に使いまわしが出来るというメリットもありますので、あえてクラス化してみました。
クラスの中にクラスを定義しているため、インスタンスを数多く生成するような使い方ではなく、プログラムの最初にインスタンス化して、あとはそれを使い続けるのがベストかと思います。
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class WatchDoc:
""" ファイル/フォルダのWatchDocクラス
"""
def __init__(self,path,func):
""" 初期処理
path(str) : 監視対象フォルダ
func : コールバック関数( func(event) )
"""
#ファイル/フォルダ変化時のイベントハンドラ
class EventHandler(FileSystemEventHandler):
def __init__(self,func):
self.func = func
def on_any_event(self,e):
self.func(e)
#Observerの生成と監視フォルダ、イベントハンドラの登録
self.func = func
self.observer = Observer()
self.observer.schedule(EventHandler(self.func), path=path, recursive=True)
def start(self):
""" 監視の開始
"""
self.observer.start()
def stop(self):
""" 監視の停止
"""
self.observer.stop()
使い方は次の通りです。監視対象のフォルダとコールバック関数(ここでは myfunc)を引数としてWatchDocクラスのインスタンスを生成し、startメソッドを呼ぶだけです。
import time
#コールバック関数
def myfunc(e):
print(f"{e.is_directory} : {e.event_type} : {e.src_path}")
#インスタンスの生成と監視の開始
wd = WatchDoc('p:/',myfunc)
wd.start()
#ループ処理
while True:
time.sleep(1)
ファイル/フォルダの 作成、削除、更新、移動 毎に処理を書く方法
ファイル/フォルダに対するイベント(作成、削除、更新、移動)は、イベントハンドラの中で個別に処理が記述できます。
ここまでの中で説明してきた on_any_event は全てのイベントを受けるハンドラなので、Windowsのシステムフォルダなどファイル更新が多いフォルダの監視では、イベントが頻繁に発生し、処理が重くなるかもしれません。
必要なイベント以外は受け付けたくない場合は、イベントハンドラに個別のメソッドを記述することで対処できます。
イベントハンドラ(メソッド)名 | 発生タイミング |
---|---|
on_modified | ファイル/フォルダが変更された時に発生 |
on_created | ファイル/フォルダが新規作成された時に発生 |
on_moved | ファイル/フォルダが移動された時に発生 |
on_deleted | ファイル/フォルダが削除された時に発生 |
on_any_event | 全てのイベントで発生 |
class EventHandler(FileSystemEventHandler):
def on_modified(self, e):
print(f"Modified: {e.src_path}")
def on_created(self,e):
print(f"Created: {e.src_path}")
def on_moved(self,e):
print(f"Moved: {e.src_path}")
def on_deleted(self,e):
print(f"Deleted: {e.src_path}")
def on_any_event(self,e):
print(f"Any Event: {e.src_path}")
最初のサンプルを上記のイベントハンドラに置き換えると次のようになります。
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
#ファイル/フォルダの変化があった時に呼ばれるイベントハンドラ
class EventHandler(FileSystemEventHandler):
def on_modified(self, e):
print(f"Modified: {e.src_path}")
def on_created(self,e):
print(f"Created: {e.src_path}")
def on_moved(self,e):
print(f"Moved: {e.src_path}")
def on_deleted(self,e):
print(f"Deleted: {e.src_path}")
def on_any_event(self,e):
print(f"Any Event: {e.src_path}")
#ファイル/フォルダの監視を開始
observer = Observer()
observer.schedule(EventHandler(), path='p:/', recursive=True)
observer.start()
#監視のためのループ処理
while True:
time.sleep(1)
下記は上記サンプルを実行した結果です。最初に on_any_event が発生してから、個々のイベントが発生していることが分かります。
まとめ
今回は PythonでWatchdog ライブラリを使ったファイル/フォルダ監視の方法と、クラス化のサンプルをご紹介しました。
watchdog ライブラリを使うと、わずか4ステップで簡単にファイル/フォルダ監視が行えます。
watchdog ライブラリには、ファイルやフォルダの作成、削除、変更、移動というイベントごとに個別の処理を記述できますが、全てのイベントを on_any_event で受けて、その中で必要なものを取捨選択するほうが、多くの場合ハンドリングしやすく、使い勝手も良いと思います。
簡単に使えるクラスのサンプルも紹介しましたので、Pythonでファイル/フォルダ監視がしたいという方は、是非この記事をお役立てください。
コメント