ファイルシステムの変更の監視

Linux + freebsdサポートを使用してFSの変更を監視するタスクを解決する完成した自転車を探して、素敵なpython watchdog lib( githubpackages.python.org )に出会いました。 興味深いOSのほかに、MacOS(独自の仕様)とWindowsもサポートしています。

私はこの質問に興味があり、著者のインド起源に怖がらない人に尋ねます



設置



PIPから完成版を入手できます。

$ pip install watchdog

PIP自体は、python-pipパッケージ、port devel / py-pipなどとしてインストールされます。

または、setup.pyを使用してソースからビルドします。



すべては、 元のマニュアルで十分に詳細に説明されています 。 確かに、バージョン0.5.4の説明があり、現在は0.6.0が関連しています。 ただし、全体の違いは、著作権の編集と4つのスペースのインデントを2のインデントに置き換えることです。「Googleコードスタイル」:)



一般に、Python自体のバージョンおよびターゲットプラットフォームには、アセンブリのかなりの数の機能があります。 これらはすべて上記のリンクで説明されていますが、必要に応じて、ロシア語で簡単に記事に追加します。



さらに、互換性のないOSでモジュールを構築することもできますが、その後、フォールバック実装が有効になり、FS構造の「キャスト」とその後の比較が行われます。 おそらくこれは誰かがそのような問題を解決するときにやったことです:)



私自身はubuntu 11.4とfreebsd-8.2リリースでビルドしようとしましたが、アセンブリと操作に問題はありませんでした。



基本的な例



ファイルとディレクトリの作成、削除、名前の変更に関連する特定のパス/パス/から/への変更に関心があるとします。



接続します:

from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler
      
      





Observerクラスは、OSの機能に基づいて/observers/__init__.pyで選択されるため、何を選択するかを自分で決める必要はありません。

FileSystemEventHandlerクラスは、変更イベントハンドラーの基本クラスです。 彼はあまり知りませんが、彼の子孫を教えます:

 class Handler(FileSystemEventHandler): def on_created(self, event): print event def on_deleted(self, event): print event def on_moved(self, event): print event
      
      





メソッドの完全なリストは、FileSystemEventHandler.dispatch自体で見ることができます:on_modified、on_moved、on_created、on_deleted。



すべてを開始します。

 observer = Observer() observer.schedule(Handler(), path='/path/to/smth', recursive=True) observer.start()
      
      







Observerはthreading.Threadの比較的遠い子孫です。それぞれ、start()を呼び出した後、変更を監視するバックグラウンドスレッドを取得します。 そのため、スクリプトがすぐに終了した場合、賢明なことは何も得られません。 期待の実装は、主に実際のプロジェクトでのモジュールのアプリケーションに依存しますが、今では松葉杖を作ることができます:

 try: while True: time.sleep(0.1) except KeyboardInterrupt: observer.stop() observer.join()
      
      





Ctrl + C(SIGINT)が到着するまで、FSの変更のイベントを待っています。その後、スレッドを終了し、完了するまで待機します。



スクリプトを実行し、次のように進みます。

 # mkdir foo # touch bar # mv bar baz # cd foo/ # mkdir foz # mv ../baz ./quz # cp ./quz ../hw # cd .. # rm -r ./foo # rm -f ./*
      
      







スクリプトの出力には次のものがあります。

 <DirCreatedEvent: src_path=/path/to/smth/foo> <FileCreatedEvent: src_path=/path/to/smth/bar> <FileMovedEvent: src_path=/path/to/smth/bar, dest_path=/path/to/smth/baz> <DirCreatedEvent: src_path=/path/to/smth/foo/foz> <FileMovedEvent: src_path=/path/to/smth/baz, dest_path=/path/to/smth/foo/quz> <FileCreatedEvent: src_path=/path/to/smth/hw> <FileDeletedEvent: src_path=/path/to/smth/foo/quz> <DirDeletedEvent: src_path=/path/to/smth/foo/foz> <DirDeletedEvent: src_path=/path/to/smth/foo> <FileDeletedEvent: src_path=/path/to/smth/hw>
      
      





イベントフィールドのHandlerクラスのメソッドは、watchdog / events.pyにリストされているFileSystemEventの子孫です

誰もがプロパティsrc_path、is_directory、event_type(「作成済み」、「削除済み」など)を持っています。 移動したイベントの場合、dest_pathプロパティが追加されます。



まあ、あなたは他に何もしたくない場合...他に何かありますか?



まず FileSystemEventHandlerの子孫があります。





PatternMatchingEventHandlerを使用して、ルールとマスクに名前が一致するFSノードでのみイベントを受信できます。



ルールは、作成時に設定されます。

 class Handler(PatternMatchingEventHandler): pass event_handler = Handler( patterns = ['*.py*'], ignore_patterns = ['cache/*'], ignore_directories = True, case_sensitive = False ) observer = Observer() observer.schedule(event_handler, path='/home/LOGS/', recursive=True)
      
      







RegexMatchingEventHandlerは同じことを行いますが、コンストラクターで明示的な正規表現式を使用します。

 class Handler(RegexMatchingEventHandler): pass event_handler = Handler( regexes = ['\.py.?'], ignore_regexes = ['cache/.*'], ignore_directories = True, case_sensitive = False )
      
      







その結果、PatternMatchingEventHandlerはパターンを内部で通常のパターンに変換するため、このようなオーバーヘッドが存在するため、動作が遅くなります。



最後に、LoggingEventHandlerはlogging.info()を介してすべてを記録します。



-それだけです。 たぶん誰かが役に立つでしょう。



PS

(およびその子)にアスキー名のないフォルダー/ファイルが含まれるディレクトリを監視する場合、ウォッチドッグの深さで例外exceptions.UnicodeEncodeErrorが発生します。 Linux(inotify)では、 watchdog.observers.inotify.Inotify._add_watchで発生します。

その理由は、ASCIIエンコーディングでコンテンツを読み取ることです。

状況を修正するには、メソッドにパッチを適用できます。

 from watchdog.observers.inotify import Inotify _save = Inotify._add_watch Inotify._add_watch = lambda self, path, mask: _save(self, path.encode('utf-8'), mask)
      
      







元の文字列の例と、encode()の処理前後のそのrepr()を次に示します。

 /home/atercattus/.wine/drive_c/users/Public/  u'/home/atercattus/.wine/drive_c/users/Public/\u0420\u0430\u0431\u043e\u0447\u0438\u0439 \u0441\u0442\u043e\u043b' '/home/atercattus/.wine/drive_c/users/Public/\xd0\xa0\xd0\xb0\xd0\xb1\xd0\xbe\xd1\x87\xd0\xb8\xd0\xb9 \xd1\x81\xd1\x82\xd0\xbe\xd0\xbb'
      
      






All Articles