我想在文件系统中的文件更改时收到通知。除了线程轮询lastModified File属性外,我什么都没有找到,显然,该解决方案不是最佳解决方案。
我想在文件系统中的文件更改时收到通知。除了线程轮询lastModified File属性外,我什么都没有找到,显然,该解决方案不是最佳解决方案。
Answers:
在较低的级别上,对该实用程序进行建模的唯一方法是在目录上进行线程轮询,并监视文件的属性。但是您可以使用模式来开发此类实用程序的适配器。
例如,诸如Tomcat之类的j2ee应用服务器和其他服务器具有自动加载功能,一旦部署描述符更改或servlet类更改,应用程序就会重新启动。
您可以使用此类服务器中的库,因为tomcat的大多数代码都是可重用的并且是开源的。
我以前写过一个日志文件监视器,发现每秒轮询几次单个文件的属性对系统性能的影响实际上很小。
Java 7作为NIO.2的一部分,添加了WatchService API
WatchService API专为需要通知文件更改事件的应用程序而设计。
我使用Apache Commons的VFS API,这是一个如何在不影响性能的情况下监视文件的示例:
Java commons-io具有FileAlterationObserver。它结合FileAlterationMonitor进行轮询。与Commons VFS类似。优点是它具有更少的依赖性。
编辑:较少的依赖项不是正确的,它们对于VFS是可选的。但是它使用Java File而不是VFS抽象层。
每次我去读取属性文件时,我都会运行此代码段,仅在自上次读取以来已对其进行了修改的情况下才实际读取该文件。希望这对某人有帮助。
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编译器接口)。尽管此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);
}
}
}