1. 概要

Java WatchService APIがJava7でリリースされるずっと前に、Apache Commons IO Monitoringライブラリは、ファイルシステムの場所またはディレクトリの変更を監視するという同じユースケースにすでに対応していました。

この記事では、2つのAPIの違いについて説明します。

2. Mavenの依存関係

Apache Commons IOを使用するには、pomに次の依存関係を追加する必要があります。

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>

そしてもちろん、監視サービスはJDKの一部であるため、外部依存関係は必要ありません。

3. 機能比較

3.1. イベントドリブン処理

WatchService APIは、オペレーティングシステムによってトリガーされるファイルシステム変更イベントによって駆動されます。 このアプローチにより、アプリケーションがファイルシステムを繰り返しポーリングして変更を行う必要がなくなります。

一方、Apache Commons IO Monitorライブラリは、 FileクラスのlistFiles()メソッドを呼び出すことにより、構成可能なスリープ間隔でファイルシステムの場所をポーリングします。 このアプローチは、特に変更が発生しない場合、CPUサイクルを浪費します。

3.2. コールバック方式

WatchServiceAPIはコールバックメソッドを提供しません。 代わりに、新しい変更イベントを処理できるかどうかを確認するための2種類のポーリングメソッドを提供します。

  1. poll()(タイムアウトパラメーター付き)や take()などのブロックメソッド
  2. poll()のようなノンブロッキングメソッド(タイムアウトパラメーターなし)

ブロッキングメソッドを使用すると、アプリケーションスレッドは、新しい変更イベントが利用可能になったときにのみ処理を開始します。 したがって、新しいイベントのポーリングを続ける必要はありません。

これらのメソッドの詳細と使用法については、こちらの記事をご覧ください。

対照的に、Apache Commons IOライブラリは、ファイルシステムの場所またはディレクトリの変更が検出されたときに呼び出されるFileAlterationListenerインターフェイスのコールバックメソッドを提供します。

FileAlterationObserver observer = new FileAlterationObserver("pathToDir");
FileAlterationMonitor monitor = new FileAlterationMonitor(POLL_INTERVAL);
FileAlterationListener listener = new FileAlterationListenerAdaptor() {
    @Override
    public void onFileCreate(File file) {
        // code for processing creation event
    }

    @Override
    public void onFileDelete(File file) {
        // code for processing deletion event
    }

    @Override
    public void onFileChange(File file) {
        // code for processing change event
    }
};
observer.addListener(listener);
monitor.addObserver(observer);
monitor.start();

3.3. イベントオーバーフロー

WatchService APIは、オペレーティングシステムのイベントによって駆動されます。 したがって、アプリケーションがイベントを十分に迅速に処理できない場合、イベントを保持するオペレーティングシステムのバッファがオーバーフローする可能性があります。 このシナリオでは、イベント StandardWatchEventKinds.OVERFLOW がトリガーされ、アプリケーションがイベントを読み取る前に、一部のイベントが失われたか破棄されたことを示します。

これには、アプリケーションで OVERFLOW イベントを適切に処理して、OVERFLOWイベントをトリガーする可能性のある突然の変更イベントをアプリケーションが確実に処理できるようにする必要があります。

一方、Commons IOライブラリは、オペレーティングシステムのイベントに基づいていないため、オーバーフローの問題はありません。

すべてのポーリングで、オブザーバーはディレクトリ内のファイルのリストを取得し、それを前のポーリングから取得したリストと比較します。

  1. 前回のポーリングで新しいファイル名が見つかった場合、 onFileCreate()がリスナーで呼び出されます
  2. 前回のポーリングで見つかったファイル名が前回のポーリングで取得したファイルリストにない場合、リスナーで onFileDelete()が呼び出されます
  3. 一致するものが見つかった場合、ファイルは、最終変更日、長さなどの属性の変更がないかチェックされます。 変更が検出されると、 onFileChange()がリスナーで呼び出されます

4. 結論

この記事では、2つのAPIの主な違いを強調することができました。

また、いつものように、この記事で使用されている例の完全なソースコードは、GitHubプロジェクトで入手できます。