2009-01-30 150 views
91

我希望在文件系统中更改文件时收到通知。我只发现了一个轮询lastModified File属性的线程,显然这个解决方案并不是最优的。Java中的文件更改监听器

+0

感谢您的回复。由于我的需求很小(我只需要重新加载一个属性文件在我的web应用程序中已更改...主要是因为重新启动整个webapp有点慢),我会坚持使用投票模式。至少现在我知道这些案例没有简单的解决方案。 – cheng81 2009-01-30 10:44:10

+13

只是一个说明。在我们发现大文件趋于缓慢进入之前,我们解决了这个问题之后,轮询机制在完全写入之前通常会发现新文件或更改文件。为了解决这个问题,采取了“两口”解决方案。轮询者注意到一个文件已经改变,但没有通知系统一个新的/已更改的文件,直到两个轮询看起来相同:即已经稳定。治愈了很多错误文件错误。 – 2012-02-22 11:23:04

+1

另一方面,Tomcat在将大型WAR文件从远程源文件放入webapps文件夹时遇到了这个问题,并且很长一段时间都这样做了。 – 2015-04-30 11:47:45

回答

19

在较低水平来模拟此实用程序的唯一方法是对目录的线程轮询和保持关注这些文件的属性。但是,您可以使用模式为这种实用程序开发适配器。

例如J2EE应用服务器,如Tomcat和其他人有一个自动加载功能在哪里,只要部署描述符的变化或Servlet类更改应用程序重新启动。

您可以使用这些服务器的库,因为tomcat的大部分代码都是可重用的并且是开源的。

+54

这在Java 7中不再是这样了:现在有一个API可以挂载到操作系统的通知服务中:http://blogs.oracle.com/thejavatutorials/entry/watching_a_directory_for_changes – 2011-09-29 10:00:06

+0

这个API非常不适合,它没有在Linux上提供关于文件关闭事件的通知。所以,给定一个简单的例子,当一个文件关闭时,将它复制到另一个目录不起作用。 – 2013-12-16 18:56:40

2

如果你愿意与一些钱JNIWrapper到部分与Winpack有用的库,你将能够获得对某些文件的文件系统事件。不幸的是窗户只。

http://www.teamdev.com/jniwrapper/index.jsf

,否则诉诸本地代码并不总是一件坏事,尤其是当所提供的最好的是轮询机制作为对本地事件。

我注意到的java文件系统的操作可以对一些电脑慢,很容易影响应用程序的性能,如果没有处理好。

27

有一个名为jnotify LIB在Linux包装inotify,并且还支持Windows。从来没有使用过它,我不知道它有多好,但值得一试我会说。

+1

它工作完美,使用起来非常简单。我一直在使用inotify多年。这是快速,稳定和可靠 – 2013-06-11 18:31:16

102

我之前写的日志文件监测器,我发现,轮询一个文件的属性,几次一秒钟的系统性能的影响,实际上是非常小的。

Java 7中,为NIO.2的部分加入了WatchService API

的WatchService API是专为需要通知有关文件更改事件的应用程序。

3

“更多NIO功能”具有文件监视功能,实现取决于底层操作系统。应该在JDK7中。

37

我使用Apache的百科全书的VFS API,这里是如何监视性能没有太大影响的文件的例子:

DefaultFileMonitor

3

我每次去阅读属性文件时都会运行这段代码,如果自上次读取文件后修改了文件,实际上只会读取该文件。希望这可以帮助某人。

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中使用了类似的方法。

7

Java commons-io有一个FileAlterationObserver。它结合FileAlterationMonitor进行轮询。类似于普通的VFS。好处是它具有更少的依赖性。

编辑:减少依赖关系不成立,它们对于VFS是可选的。但它使用java File而不是VFS抽象层。

1

您可以使用FileReader监听文件更改。 PLZ见下文

// 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(); 
    } 
} 
0

轮询示例中的最后一次修改文件属性是一个简单而有效的解决方案,但。只要定义一个类扩展我的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

类似于其他的答案,这里是它的使用文件,计时器,和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); 
    } 

    } 
}