2012-04-08 6 views
3

ファイルシステム内でエントリを変更する際にエントリを更新したいメディアライブラリについて、私は 'new' java.nio file watching featuresthis exampleを使って試してください。
私は移動(名前を変更)または削除が、ここでは(まだ他のオペレーティングシステムを試していない)Windows7の上のフォルダを見ていたときに何が起こっているかで、ファイルが作成されているときに便利なイベントを取得するために期待していた。java.nioを使用してファイル変更時に作成/移動/削除イベントを発生させる

フォーマット:
は 【のthreadName] 2012-04-09 18 DEBUG:20:35.934 GroupNumber-コマンド:パス
のthreadName:同じGroupNumberで送信されたメッセージがされている:各ウォッチフォルダは異なるID
GroupNumberを有するそれ自身のスレッドで実行され同時に送信されます(通常..)
COMMAND:受信したコマンド
パス:受信したパス012代わりに、単一イベントを有する

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つのコマンドで構成されますが、名前変更と「同じフォルダ内での移動」はdeleteコマンドで開始しますが、将来のコマンドで定義されます。さらに、複数のファイルは、例えば、並行して移動すると、何らかの方法でソートされなければならない異なる操作に属するコマンドのランダムなリストになります。

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

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 

もサポートしなければならないより複雑な例では、小さなファイルが移動されています。

答えて

2

java nioファイルウォッチャーにはあまりよく慣れていませんが、ファイルシステムからイベントを取得するのにjnotify libraryを使用しました。これは非常に良く、WindowsとLinuxで作業していました。

使用したい場合はNIO任意の方法、ここで見てみましょうしよう:私が見たhttps://blogs.oracle.com/thejavatutorials/entry/watching_a_directory_for_changes

+0

私は今フレームワークに含まれている関数を使用したいと思いますが、jnotifyは私が望むものとまったく同じように見えるので、より良いかもしれません。 – Philippe

3

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

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); 
    } 

} 

あなたも、あなたのロックオブジェクトeventEntrySyncObjを必要としないし、あなたの呼び出し可能/コマンドがありfileWatchActionイベントを発生させるために必要なすべての情報

+0

きれいに見えます。イベントを延期しない場合、いつ削除を実行しますか?これは名前の変更や移動の開始になる可能性があります。 – Philippe

+0

現在、各イベントのFileWatchActionを作成します。 – andih

+2

'int count = 0; for(WatchEvent イベント:key.pollEvents()){++ count; ...} log.debug( "Handled {} events"、count); 'mv/renameは、一緒に属している1つのキーに対して2つのイベントを作成することがわかります。したがって、各イベントをWatchhandlerに渡す代わりに、KeyをWatchHandlerに渡して、WatchHandlerが一緒に属するイベントをポーリングできるようにすることができます。もう1つの最適化は、複数のMonitorThread/ManagedFolderWatcherを使用することです。 – andih

2

取得しているイベントは、取得しようとしているイベントです。 Windowsの場合。 Linuxでは、フォルダを見るとそのフォルダのイベントだけを取得し、そのフォルダのファイルは取得しません。私はそれがOS X上ではそれほど難しいとは思っていますが、そこでは決して扱っていません。これは、あなたが/tmpあなたがENTRY_CREATE /tmp/tmp/なくENTRY_CREATE /tmp/tmp/test.avi

が表示されます監視していた場合、私はその後、定期的にセットで言及したすべてのファイルを操作、設定の変更通知を蓄積し、フォルダを見て、同じような問題を取り扱うことを意味します。 (セットが更新され、別のセットがスキャンされてクリアされていて、セットがどのセットであったかを交換していました)

要するに、ファイルが移動、コピー、または追加されたときを把握しようとしました。に。私は単にすべての作成または修正を、以前のファイルとは無関係の新しいファイルを作成するものとして扱いました。少なくとも私の場合、サーバー上の何百万ものファイルを追跡していた場所では、実際にはそれ以上のことは実行できませんでした。

+0

入力いただきありがとうございます。 oracleがレイヤーを実装するのを忘れてしまったようです...開始前に、ファイル変更リスナーを追加し、メッセージ処理を自分で実装しなくても、このように通知することを期待していました。たぶん、彼らは同じ結論に達していたかもしれません。「それ以上のものは、実際には役に立たないものでした」。この機能は、今私にとって全く役に立たないようです。 – Philippe

+0

@Philippe、私は私の状況にとって非常に貴重な機能を発見しました。私は創造の大きな動機の1つは、外部アクションを介して変更されたファイルリストのようにフォルダ内のファイルのリストを表示するUIウィンドウをライブ更新する機能であったと考えています。イベントを逃さないためには、非常に低いレベルで実装する必要があるため、ファイルシステム全体の速度低下を避けるためには非常にシンプルで効率的でなければなりません。あなたはこのファイル変更情報を使って何をしたいのかは決して言わなかったので、もっと助けてはいけません。私にとっては、再スキャンを開始するだけで十分でした。 –

+0

私のアプリケーションは、DLNA経由でストリーミングされるビデオ、オーディオ、およびイメージファイルを管理します。現在、新しいファイルを追加するにはスキャンボタンを押す必要があります。私は構成されたフォルダを見て、ファイルがディスクに完全に書き込まれたときにファイル変更時に自動的にアクションをトリガするように変更したいと思う。作成:新しいファイルをスキャンし、データをライブラリに挿入し、移動/名前変更:メディアライブラリ内のファイルのパスを更新し、削除:メディアライブラリからデータを削除します。私はすべてのケースをカバーする方法、特に異なるドライブ上のフォルダを見るための作成と移動を区別することはできません。 – Philippe

関連する問題