4

ファイル システムでエントリが変更されたときにエントリを更新したいメディア ライブラリの場合、この例を使用して、「新しい」java.nioファイル ウォッチング機能を試してみました。 ファイルが作成、移動 (名前変更)、または削除されたときに有用なイベントが発生することを期待していましたが、windows7 でフォルダーを監視しているときに何が起こっているかを示します (他のオペレーティング システムはまだ試していません)。

フォーマット:
[ThreadName] DEBUG 2012-04-09 18:20:35.934 GroupNumber-COMMAND: パス
ThreadName: 各監視フォルダは、個別の ID GroupNumber を持つ独自のスレッドで実行されます
: 同じ GroupNumber で送信されたメッセージが同時に送信されています(通常..)
COMMAND: 受信したコマンド
Path: 受信したパス

Rename:
[Watch0] DEBUG 2012-04-09 18:20:35.934 2-ENTRY_DELETE: C:\tmp\tmp\test.avi
[Watch0] DEBUG 2012-04-09 18:20:35.935 2-ENTRY_CREATE: C:\tmp\tmp\test1.avi
[Watch0] DEBUG 2012-04-09 18:20:35.936 3-ENTRY_MODIFY: C:\tmp\tmp
[Watch0] DEBUG 2012-04-09 18:20:35.937 4-ENTRY_MODIFY: C:\tmp\tmp\test1.avi

[Watch4] DEBUG 2012-04-09 18:43:47.965 18-ENTRY_DELETE: F:\tmp\test.avi
[Watch4] DEBUG 2012-04-09 18:43:47.966 18-ENTRY_CREATE: F:\tmp\test1.avi
[Watch4] DEBUG 2012-04-09 18:43:47.967 19-ENTRY_MODIFY: F:\tmp\test1.avi

Create:
[Watch0] DEBUG 2012-04-09 18:22:02.055 5-ENTRY_CREATE: C:\tmp\test.avi
[Watch0] DEBUG 2012-04-09 18:22:02.066 6-ENTRY_MODIFY: C:\tmp\test.avi
[Watch0] DEBUG 2012-04-09 18:22:03.460 7-ENTRY_MODIFY: C:\tmp\test.avi
//Note the 1.4'' delay between the last two messages. 
//This is the time required to actually copy the file

Move in same watch folder:
[Watch0] DEBUG 2012-04-09 18:18:42.395 0-ENTRY_DELETE: C:\tmp\test.avi
[Watch0] DEBUG 2012-04-09 18:18:42.396 0-ENTRY_MODIFY: C:\tmp\tmp
[Watch0] DEBUG 2012-04-09 18:18:42.396 1-ENTRY_CREATE: C:\tmp\tmp\test.avi
[Watch0] DEBUG 2012-04-09 18:18:42.396 1-ENTRY_MODIFY: C:\tmp\tmp\test.avi

Move to other watch folder on same drive:
[Watch1] DEBUG 2012-04-09 18:23:24.341 8-ENTRY_CREATE: C:\tmp2\test.avi
[Watch0] DEBUG 2012-04-09 18:23:24.341 8-ENTRY_DELETE: C:\tmp\test.avi
[Watch1] DEBUG 2012-04-09 18:23:24.342 10-ENTRY_MODIFY: C:\tmp2\test.avi
//The two 8 are lying. Both messages are being sent from different threads
//and the shared counter hasn't been incremented by any yet. The next entry has been 
//incremented by two!

Move to other watch folder on different drive:
[Watch4] DEBUG 2012-04-09 18:25:42.324 11-ENTRY_CREATE: F:\tmp\test.avi
[Watch4] DEBUG 2012-04-09 18:25:42.338 12-ENTRY_MODIFY: F:\tmp\test.avi
[Watch4] DEBUG 2012-04-09 18:25:42.703 13-ENTRY_MODIFY: F:\tmp\test.avi
[Watch3] DEBUG 2012-04-09 18:25:49.433 14-ENTRY_DELETE: C:\tmp2\test.avi
//Note that the last delete message is being sent from another thread then the first ones.
//This is because the source and destination WatchDirs aren't the same

Delete:
[Watch9] DEBUG 2012-04-05 21:22:02.921 ENTRY_DELETE: C:\tmp\test (2011).mkv

単一のイベントを持つ代わりに、解釈する必要がある一連の「コマンド + パス」があります。たとえば、削除は単一のコマンドで構成されますが、名前の変更と「同じフォルダに移動」も削除コマンドで始まりますが、将来のコマンドによって定義されます。さらに、複数のファイルを並行して移動するなど、さまざまな操作に属するコマンドのランダムなリストになる可能性があり、何らかの方法で並べ替える必要があります。

私が思いつくことができる最高のものは、このクラスです。イベントは受信時にキューに入れられ、別のスレッドで受信された直後 (1 秒) にチェックされます (他のイベントが生成され、同じスレッドに属している場合に時間を与えるため)。 「イベントグループ」)。

これは、単一のファイルの名前変更、移動、作成、または削除の場合は機能しますが、複数のファイルを並行してコピーしたり、ファイルのバッチをコピーしたりすると、何も機能しなくなります。

必要なものの実装は既に存在しますか (一般的な使用例のようです)? または、すべてのケースをカバーするためにこの問題にアプローチする方法を誰かが知っていますか?

最終的には、Windows、Linux、および OSX で動作する必要があります。

同様にサポートされるべきより複雑な例

[Watch0] DEBUG 2012-04-09 19:10:17.774 0-ENTRY_CREATE: C:\tmp\tmp\testlarge.avi
[Watch0] DEBUG 2012-04-09 19:10:17.825 0-ENTRY_MODIFY: C:\tmp\tmp\testlarge.avi
[Watch0] DEBUG 2012-04-09 19:10:17.826 1-ENTRY_MODIFY: C:\tmp\tmp
[Watch0] DEBUG 2012-04-09 19:12:09.516 2-ENTRY_DELETE: C:\tmp\tmp\testsmall.avi
[Watch0] DEBUG 2012-04-09 19:12:09.516 3-ENTRY_CREATE: C:\tmp\testsmall.avi
[Watch0] DEBUG 2012-04-09 19:12:09.517 3-ENTRY_MODIFY: C:\tmp\testsmall.avi
[Watch0] DEBUG 2012-04-09 19:12:09.521 4-ENTRY_MODIFY: C:\tmp\tmp
[Watch0] DEBUG 2012-04-09 19:14:13.025 5-ENTRY_MODIFY: C:\tmp\tmp\testlarge.avi

ここでは、大きなファイルを作成しながら、小さなファイルを移動しています。

4

3 に答える 3

3

あなたが得ようとしているイベントはあなたが得ようとしているイベントです。Windowsの場合。Linuxでは、フォルダーを監視すると、そのフォルダー内のファイルではなく、そのフォルダーのイベントのみが取得されます。私はOSXでそれを扱ったことがありませんが、それはOSXではさらに厄介だと思います。これは、あなたが見ている場合、あなたは/tmp見るENTRY_CREATE /tmp/tmp/が見えないことを意味しますENTRY_CREATE /tmp/tmp/test.avi

フォルダーを監視し、変更通知をセットに蓄積してから、セットに記載されているすべてのファイルを定期的に操作することで、同様の問題を処理しました。(1つのセットが更新され、別のセットがスキャンおよびクリアされたため、どのセットがどちらであるかを交換しました。)

つまり、ファイルがいつ移動、コピー、または追加されたかを把握することを諦めました。私は、すべての作成または変更を、以前のファイルとは関係のない新しいファイルを作成するものとして単純に扱いました。少なくとも私の場合、サーバー上の何百万ものファイルを追跡していたので、それ以上のものは実際には機能しませんでした。

于 2012-04-19T03:31:41.497 に答える
3

Java nio ファイル ウォッチャーにはあまり詳しくありませんが、jnotify ライブラリを使用してファイル システムからイベントを取得しました。これは非常に優れており、Windows と Linux で動作していました。

何らかの方法で nio を使用したい場合は、こちらをご覧ください: https://blogs.oracle.com/thejavatutorials/entry/watching_a_directory_for_changes

于 2012-04-08T15:20:39.690 に答える
3

私が見たことの 1 つは、イベントごとに新しいスレッドを作成し、ロック オブジェクトを使用してスレッドを同期することです。

ExecutorService を作成する場合、つまり次のようにコードを書き直すとよいでしょう。

private ExecutorService executorService;


private class WatchEventHandler implements Callable {

    WatchEvent<?> event;

    public WatchEventHandler(final WatchEvent<?> event) {
        this.event = event;
    }

    @Override
    public void call() throws Exception{
        // do something with the event

        // fireFileWatchAction();


    }    
}


public ManagedFolderWatcher(DOManagedFile managedFolder) throws IOException {
   executorService = Executors.newFixedThreadPool(10);
   ...
}

そしてあなたの実行/プロセスイベントメソッドで

public void run() {
    try {
       while(true) {

          WatchKey key = watcher.take();
          ....

          for (WatchEvent<?> event : key.pollEvents()) {
              ...
              // in my oppinon there is no need to delay the event 
              executorService.schedule(new WatchEventHandler(event));
          }
          ...

       }
    } catch (InterruptedException ie) {
        // todo: propper error handling
        log.error("Thread interrupted", ie);
    } catch (ClosedWatchServiceException cwse) {
        // todo: propper error handling
        log.error("WatchService allready closed.", cwse);
    }

} 

この方法で実装すると、ロック オブジェクトも必要なくなり、eventEntrySyncObjCallable/Command には fileWatchAction イベントを発生させるために必要なすべての情報が含まれます。

于 2012-04-08T18:56:26.507 に答える