ファイルシステムでファイルが変更されたときに通知を受け取りたい。私は、lastModified Fileプロパティをポーリングするスレッドしか見つけていません。明らかに、このソリューションは最適ではありません。
ファイルシステムでファイルが変更されたときに通知を受け取りたい。私は、lastModified Fileプロパティをポーリングするスレッドしか見つけていません。明らかに、このソリューションは最適ではありません。
回答:
低レベルでこのユーティリティをモデル化する唯一の方法は、ディレクトリをスレッドでポーリングし、ファイルの属性を監視することです。ただし、パターンを使用して、このようなユーティリティのアダプタを開発できます。
たとえば、Tomcatなどのj2eeアプリケーションサーバーには、デプロイメント記述子が変更されるか、サーブレットクラスが変更されるとすぐにアプリケーションが再起動する自動ロード機能があります。
Tomcatのほとんどのコードは再利用可能でオープンソースであるため、このようなサーバーのライブラリを使用できます。
以前にログファイルモニターを作成したことがあり、1秒間に数回、単一ファイルの属性をポーリングすることによるシステムパフォーマンスへの影響は実際には非常に小さいことがわかりました。
NIO.2の一部としてJava 7にWatchService APIが追加されました
WatchService APIは、ファイル変更イベントについて通知を受ける必要があるアプリケーション用に設計されています。
私はApache CommonsのVFS APIを使用しています。パフォーマンスに大きな影響を与えずにファイルを監視する方法の例を次に示します。
Java commons-ioにはFileAlterationObserverがあります。FileAlterationMonitorと組み合わせてポーリングを行います。Commons VFSに似ています。利点は、依存関係がはるかに少ないことです。
編集:依存関係を減らすことは正しくありません。VFSではオプションです。ただし、VFS抽象化レイヤーの代わりにjavaファイルを使用します。
プロパティファイルの読み取りに行くたびに、このコードスニペットを実行します。実際にファイルを読み取るのは、最後に読み取ってから変更されている場合のみです。これが誰かを助けることを願っています。
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
ます。
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();
}
}
あなたがお金を手放すことをいとわないなら、JNIWrapperはWinpackを備えた便利なライブラリです、あなたは特定のファイルでファイルシステムイベントを得ることができるでしょう。残念ながら窓のみ。
https://www.teamdev.com/jniwrapperを参照してください。
それ以外の場合、ネイティブコードを使用することは必ずしも悪いことではありません。特に、ネイティブイベントに対するポーリングメカニズムが最善の場合です。
一部のコンピューターではJavaファイルシステムの動作が遅くなり、適切に処理しないとアプリケーションのパフォーマンスに簡単に影響する可能性があることに気付きました。
また、Apache Commons JCI(Java Compiler Interface)を検討することもできます。このAPIはクラスの動的コンパイルに重点を置いているようですが、ファイルの変更を監視するAPIのクラスも含まれています。
Spring Integrationは、ディレクトリとファイルを監視するための優れたメカニズムを提供します:http : //static.springsource.org/spring-integration/reference/htmlsingle/#files。クロスプラットフォームであることを確認してください(Mac、Linux、Windowsで使用しました)。
JxFileWatcherと呼ばれる、ファイルとフォルダを監視するための商用クロスデスクトップライブラリがあります。こちらからダウンロードできます:http : //www.teamdev.com/jxfilewatcher/
また、オンラインでそれを見ることができます:http : //www.teamdev.com/jxfilewatcher/onlinedemo/
最後に変更されたファイルプロパティのポーリングは、シンプルですが効果的なソリューションです。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();
}
他の回答と同様に、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);
}
}
}