Javaのファイル変更リスナー


104

ファイルシステムでファイルが変更されたときに通知を受け取りたい。私は、lastModified Fileプロパティをポーリングするスレッドしか見つけていません。明らかに、このソリューションは最適ではありません。


すべての応答をありがとう。私のニーズは小さいので(変更したプロパティファイルをWebアプリケーションで再ロードする必要があるだけです。主に、Webアプリケーション全体の再起動が少し遅いため)、ポーリングモデルを使い続けます。少なくとも今、私はこれらのケースに簡単な解決策がないことを知っています。
cheng81 2009年

14
ただのメモ。大きなファイルの読み込みが遅い傾向が見られる前にこの問題を解決したところ、ポーリングメカニズムは、完全に書き込まれる前に新しいファイルまたは変更されたファイルを発見することがよくありました。これを解決するために、「2バイト」ソリューションが採用されました。ポーラーは、ファイルが変更されたことに気づきましたが、2つのポーリングで同じに見えるまで、つまり安定化するまで、システムに新規/変更されたファイルを通知しませんでした。多くのbadfileエラーを修正しました。
スティーブ・パウエル

1
余談ですが、Tomcatは、大きなWARファイルをリモートソースからwebappsフォルダーにドロップするときにその問題を抱えており、長い間そうしてきました。
John Rix、2015

回答:


21

低レベルでこのユーティリティをモデル化する唯一の方法は、ディレクトリをスレッドでポーリングし、ファイルの属性を監視することです。ただし、パターンを使用して、このようなユーティリティのアダプタを開発できます。

たとえば、Tomcatなどのj2eeアプリケーションサーバーには、デプロイメント記述子が変更されるか、サーブレットクラスが変更されるとすぐにアプリケーションが再起動する自動ロード機能があります。

Tomcatのほとんどのコードは再利用可能でオープンソースであるため、このようなサーバーのライブラリを使用できます。


59
これは、Java 7にはもはや真実ではありません:OSの通知サービスにフックすることができ、このためのAPIは、今があります:blogs.oracle.com/thejavatutorials/entry/...
Arnout Engelen

そのAPIは非常に不十分であり、Linuxでのファイルクローズイベントの通知を提供しません。したがって、単純なケースを考えると、ファイルが閉じているときに、そのファイルを別のディレクトリにコピーしても機能しません。
binarytemple_picsolve 2013

117

以前にログファイルモニターを作成したことがあり、1秒間に数回、単一ファイルの属性をポーリングすることによるシステムパフォーマンスへの影響は実際には非常に小さいことがわかりました。

NIO.2の一部としてJava 7にWatchService APIが追加されました

WatchService APIは、ファイル変更イベントについて通知を受ける必要があるアプリケーション用に設計されています。


10
例はディレクトリを監視しているように見えますが、個々のファイルはどうですか?
アルキメデストラハノ

@ArchimedesTrajano APIは、ディレクトリ内のファイルが変更されたときに通知します。トリガーされるイベントには、変更されたファイルの名前が含まれます。したがって、特定のファイルのイベントを処理し、他のファイルを無視することができます。
マイケル



27

Linuxでinotifyをラップするjnotifyと呼ばれるライブラリがあり、Windowsもサポートしています。使ったことはなく、どれほど良いかわかりませんが、試してみる価値はあります。


1
それは完璧に機能し、使用は非常に簡単です。私は長年inotifyを使用しています。それは、高速で安定性と信頼性である
oᴉɹǝɥɔ

8

Java commons-ioにはFileAlterationObserverがあります。FileAlterationMonitorと組み合わせてポーリングを行います。Commons VFSに似ています。利点は、依存関係がはるかに少ないことです。

編集:依存関係を減らすことは正しくありません。VFSではオプションです。ただし、VFS抽象化レイヤーの代わりにjavaファイルを使用します。


4

「その他のNIO機能」にはファイル監視機能があり、実装は基盤となるOSに依存します。JDK7にある必要があります。


もっと具体的になったり、ドキュメントへのリンクを投稿したりできますか?これで何かを見つけることができないようです...
ルチアーノ

パッケージのようjava.nio.fileです。チュートリアルをご覧ください
デビッドL.

4

プロパティファイルの読み取りに行くたびに、このコードスニペットを実行します。実際にファイルを読み取るのは、最後に読み取ってから変更されている場合のみです。これが誰かを助けることを願っています。

private long timeStamp;
private File file;

private boolean isFileUpdated( File file ) {
  this.file = file;
  this.timeStamp = file.lastModified();

  if( this.timeStamp != timeStamp ) {
    this.timeStamp = timeStamp;
    //Yes, file is updated
    return true;
  }
  //No, file is not updated
  return false;
}

Log4Jでも同様のアプローチが使用されていFileWatchdogます。


2

FileReaderを使用してファイルの変更をリッスンできます。下の例を見てください

// File content change listener 
private String fname;
private Object lck = new Object();
... 
public void run()
{
    try
    {
        BufferedReader br = new BufferedReader( new FileReader( fname ) );
        String s;
        StringBuilder buf = new StringBuilder();
        while( true )
        {
            s = br.readLine();
            if( s == null )
            {
                synchronized( lck )
                {
                    lck.wait( 500 );
                }
            }
            else
            {
               System.out.println( "s = " + s );
            }

        }
    }
    catch( Exception e )
    {
        e.printStackTrace();
    }
}

2

あなたがお金を手放すことをいとわないなら、JNIWrapperはWinpackを備えた便利なライブラリです、あなたは特定のファイルでファイルシステムイベントを得ることができるでしょう。残念ながら窓のみ。

https://www.teamdev.com/jniwrapperを参照してください

それ以外の場合、ネイティブコードを使用することは必ずしも悪いことではありません。特に、ネイティブイベントに対するポーリングメカニズムが最善の場合です。

一部のコンピューターではJavaファイルシステムの動作が遅くなり、適切に処理しないとアプリケーションのパフォーマンスに簡単に影響する可能性があることに気付きました。


1

また、Apache Commons JCI(Java Compiler Interface)を検討することもできます。このAPIはクラスの動的コンパイルに重点を置いているようですが、ファイルの変更を監視するAPIのクラスも含まれています。

例:http : //commons.apache.org/jci/usage.html




1

最後に変更されたファイルプロパティのポーリングは、シンプルですが効果的なソリューションです。my FileChangedWatcherを拡張するクラスを定義し、onModified()メソッドを実装するだけです。

import java.io.File;

public abstract class FileChangedWatcher
{
    private File file;

    public FileChangedWatcher(String filePath)
    {
        file = new File(filePath);
    }

    public void watch() throws InterruptedException
    {
        long currentModifiedDate = file.lastModified();

        while (true)
        {
            long newModifiedDate = file.lastModified();

            if (newModifiedDate != currentModifiedDate)
            {
                currentModifiedDate = newModifiedDate;
                onModified();
            }

            Thread.sleep(100);
        }
    }

    public String getFilePath()
    {
        return file.getAbsolutePath();
    }

    protected abstract void onModified();
}

0

他の回答と同様に、File、Timer、TimerTaskを使用して、設定された間隔でポーリングをバックグラウンドスレッドポーリングとして実行する方法を次に示します。

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

public class FileModifiedWatcher
{
  private static File file;
  private static int pollingInterval;
  private static Timer fileWatcher;
  private static long lastReadTimeStamp = 0L;

  public static boolean init(String _file, int _pollingInterval)
  {
    file =  new File(_file);
    pollingInterval = _pollingInterval; // In seconds

    watchFile();

    return true;
  }

  private static void watchFile()
  {
    if ( null == fileWatcher )
    {
      System.out.println("START");

      fileWatcher = new Timer();

      fileWatcher.scheduleAtFixedRate(new TimerTask()
      {
        @Override
        public void run()
        {

          if ( file.lastModified() > lastReadTimeStamp )
          {
            System.out.println("File Modified");
          }

          lastReadTimeStamp = System.currentTimeMillis();
        }
      }, 0, 1000 * pollingInterval);
    }

  }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.