Java监控文件目录的变化
2015-01-15 19:19
471 查看
在Java1.7以前的版本中,如果程序想要监控文件的变化,比较常规的做法是轮询要监控的文件目录,采用启动一条后台线程。这种做法性能较差尤其对于大批量的文件监控。第三方commons-io.jar包有org.apache.commons.io.monitor类利用观察者模式也可用做文件的监控。
1.7版本后,java.nio.file包提供了目录监控的api即 Watch Service API。我们把想要监控的目录注册进watchservice中,你把想要监控的事件告诉service,比如文件创建,删除,修改。当service检测到所关注的事件,系统的注册的线程就是检测到并做出相应处理。
WatchKeys是线程安全的,可以和 java.nio.concurrent包中的类使用也可以放入 thread
pool中使用。
基本步骤:
1,为文件系统创建WatchService
2,所有实现了 Watchable 接口的对象才可以被注册进watchService中。Path类实现了Watchable接口,所以我们要监控的文件路径都要获取它的Path对象。
Path path = Paths.get(fileDirectory)
Path类实现了2个register方法。我们使用 register(WatchService, WatchEvent.Kind<?>...)。有三个参数版本的register方法暂时还没有实现。(第三个参数WatchEvent.Modifier直到JDK1.8还没有给出实现)。
可以监听的事件类型有
3,事件处理的过程
首先,获取key,有三种方法获得watch key.
poll – 获取并删除就绪队列中的key。若可用,返回就绪队列中的key。不可用就返回null值。
poll(long, TimeUnit) – 与poll相同,只是等待TimeUnit的时间
take – 获取可用key.没有可用的就wait
然后,利用key.pollEvents()方法获取WatchEvents的list集合,利用kind()方法获取事件的类型,context()方法获取文件名,count()方法获取次数。
最后事件处理完后,我们需要调用key.reset()方法使key重置到ready状态。若reset()方法返回false,说明key已经失效了,循环可以退出了。这一步很重要,若没有调用reset()方法,则当前的key就不再会获取将来发生的事件。
一个watch key在它的生命周期内有以下3种状态。
调用cancel方法明确的使其失效
文件系统目录变成不可进入
watch service 关闭了
一个例子:
MyWatchService.java
结果如下
1.7版本后,java.nio.file包提供了目录监控的api即 Watch Service API。我们把想要监控的目录注册进watchservice中,你把想要监控的事件告诉service,比如文件创建,删除,修改。当service检测到所关注的事件,系统的注册的线程就是检测到并做出相应处理。
WatchKeys是线程安全的,可以和 java.nio.concurrent包中的类使用也可以放入 thread
pool中使用。
基本步骤:
1,为文件系统创建WatchService
WatchService watcher = FileSystems.getDefault().newWatchService();
2,所有实现了 Watchable 接口的对象才可以被注册进watchService中。Path类实现了Watchable接口,所以我们要监控的文件路径都要获取它的Path对象。
Path path = Paths.get(fileDirectory)
Path类实现了2个register方法。我们使用 register(WatchService, WatchEvent.Kind<?>...)。有三个参数版本的register方法暂时还没有实现。(第三个参数WatchEvent.Modifier直到JDK1.8还没有给出实现)。
可以监听的事件类型有
ENTRY_CREATE– 新文件创建
ENTRY_DELETE– 文件删除
ENTRY_MODIFY– 文件修改
OVERFLOW– 表示当前的事件可能丢失或被忽略掉,通常我们不用注册这个事件。
Path dir = ...; try { WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); } catch (IOException x) { System.err.println(x); }
3,事件处理的过程
首先,获取key,有三种方法获得watch key.
poll – 获取并删除就绪队列中的key。若可用,返回就绪队列中的key。不可用就返回null值。
poll(long, TimeUnit) – 与poll相同,只是等待TimeUnit的时间
take – 获取可用key.没有可用的就wait
然后,利用key.pollEvents()方法获取WatchEvents的list集合,利用kind()方法获取事件的类型,context()方法获取文件名,count()方法获取次数。
最后事件处理完后,我们需要调用key.reset()方法使key重置到ready状态。若reset()方法返回false,说明key已经失效了,循环可以退出了。这一步很重要,若没有调用reset()方法,则当前的key就不再会获取将来发生的事件。
一个watch key在它的生命周期内有以下3种状态。
Ready表示key已经准备好接受事件。当key建立时,它就处于这个状态。
Signaled表示有一个或多个事件在排队等待。一旦一个key被signaled,它就不处于ready状态了,知道reset()重置以后。
Invalid表示当前key已经不可用了。. 造成Invalid的原因可能有下面几个
调用cancel方法明确的使其失效
文件系统目录变成不可进入
watch service 关闭了
一个例子:
package filewatch; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Paths; import java.nio.file.StandardWatchEventKinds; import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; public class FileWatchTask implements Runnable { private String fileDirectory; public FileWatchTask(String fileDirectory) { this.fileDirectory = fileDirectory; } public void run() { WatchService watchService = null; try { //获取当前文件系统的WatchService监控对象 watchService = FileSystems.getDefault().newWatchService(); } catch (IOException e) { e.printStackTrace(); } try { //获取文件目录下的Path对象注册到 watchService中。 //监听的事件类型,有创建,删除,以及修改 Paths.get(fileDirectory) .register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); } catch (IOException e) { e.printStackTrace(); } while (true) { WatchKey key = null; try { //获取可用key.没有可用的就wait key = watchService.take(); } catch (InterruptedException e) { e.printStackTrace(); } for (WatchEvent<?> event : key.pollEvents()) { //todo System.out.println(event.context() + "文件:" + event.kind() + "次数: " + event.count()); } //重置,这一步很重要,否则当前的key就不再会获取将来发生的事件 boolean valid = key.reset(); //失效状态,退出监听 if (!valid) { break; } } } }
MyWatchService.java
package filewatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MyWatchService { public static void main(String[] args) throws Exception { String propFileName = "D:\\sources\\"; //要监控的文件目录 //因为是线程安全的所以可以放入ThreadPool中使用 ExecutorService cachedThreadPool = Executors.newFixedThreadPool(1); cachedThreadPool.execute(new FileWatchTask(propFileName)); } }
结果如下
相关文章推荐
- java 实现监控某目录文件变化
- Java 如何监控文件目录的变化 【转】
- JAVA实时监控目录下文件的变化
- Java实现监控目录下文件变化
- java 使用线程监控文件目录变化的实现方法
- java 使用线程监控文件目录变化的实现方法
- java读取系统Properties配置文件利用线程实时监控配置文件变化
- [SHELL]监控LINUX目录文件变化
- java读取系统Properties配置文件利用线程实时监控配置文件变化
- Python for Windows——监控Windows某个目录下文件的变化
- java监控路径下文件变化
- java实现文件变化监控的方法(推荐)
- 监控目录文件变化的ReadDirectoryChangesW 函数学习总结
- Java监控文件变化
- python监控文件或目录变化
- 使用线程监控文件目录变化
- Java高效监控文件目录
- java监控文件夹内文件变化并且进行文件同步bigfilesync
- C# 利用FTP自动下载xml文件后利用 FileSystemWatcher 监控目录下文件变化并自动更新数据库
- java监控目录文件