利用WatchService实现文件监视
Java.nio.file WatchService类图
- FileSystem:当前系统默认的文件系统。
- WatchService:文件系统监视服务的接口类,它的具体实现由监视服务提供者负责加载(不同的操作系统实现不同的加载类,如windows的WindowsWatchService类)。
- Watchable:实现了Watchable接口的对象才能注册监视服务WatchService,由于Path类实现了Watchable接口,固可以通过Path类对文件目录进行监听。
- WatchKey:该类代表着WatchService类和Watchable类的注册关系,WatchKey在Watchable对象(Path对象)向WatchService注册的时候被创建。
实现代码与解析
/*
* 创建所需要监控目录树的根目录File对象。
* */
File file = new File("/delete");
/*
* 转换成Path对象。
* */
Path parentPath = file.toPath();
/*
*创建监视服务类WatchService对象。
* */
WatchService watchService = FileSystems.getDefault().newWatchService();
/*
* 对根目录注册监听服务。
* 1.ENTRY_CREATE:创建条目时返回的事件类型
* 2.ENTRY_DELETE:删除条目时返回的事件类型
* 3.ENTRY_MODIFY:修改条目时返回的事件类型
* 4.OVERFLOW:表示事件丢失或被丢弃,不必要注册该事件类型
* */
parentPath.register(watchService
, StandardWatchEventKinds.ENTRY_CREATE
,StandardWatchEventKinds.ENTRY_DELETE
,StandardWatchEventKinds.ENTRY_MODIFY);
/*
* -------遍历根目录及子目录,将其全都注册监听服务-------
* 创建链表结构存储File对象。
* 添加根目录的对象到链表尾。
* */
LinkedList<File> linkfile = new LinkedList<>();
linkfile.addLast(file);
/*
* 当链表还有File对象时进入循环。
* */
while(linkfile.size()>0){
/*
* 移除链表表头的File对象并返回给f
* 使用listFiles()方法生成File数组,
* 数组储存f代表目录中的File对象。
* */
File f = linkfile.removeFirst();
File[] files = f.listFiles();
for (File f1:files
) {
/*
* 遍历数组中的每一个File对象。
* 判断其是不是目录,
* 如果是目录则将其添加到链表尾,
* 只有目录可以注册监听服务。
* */
if(f1.isDirectory()){
linkfile.addLast(f1);
/*
* 给当前目录注册监听服务。
* */
f1.toPath().register(watchService
, StandardWatchEventKinds.ENTRY_CREATE
,StandardWatchEventKinds.ENTRY_DELETE
,StandardWatchEventKinds.ENTRY_MODIFY);
}
}
}
/*
* 创建一个线程用来获取监听事件WatchEvent对象
* */
new Thread(()->{
/*
* 构建无限循环等待事件发生
* */
while(true){
/*
* 通过WatchService对象tack()方法产生WatchKey实例key
* */
WatchKey key = null;
try {
key = watchService.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
/*
* WatchKey对象key轮询事件(pollEvents())获得事件队列
* 遍历事件(WatchEvent)获得变化文件的信息
* */
for (WatchEvent event: key.pollEvents()
) {
/*
* event.context()返回Object类型,可转化为String和Path类型。
* event.kind()返回事件种类。
* */
Path file2 = (Path)event.context();
String str = file2.toFile().getAbsolutePath();
System.out.println(str+" "+event.kind().toString());
}
/*
* 重置WatchKey对象,使事件对象回到队列。
* */
key.reset();
}
}).start();
/*
* 测试代码,改变文件
* */
new File("/delete/123.txt").createNewFile();
new File("/delete/create").mkdir();
new File("/delete/234.txt").delete();
new File("/delete/create/456.txt").createNewFile();
/*
* Output:
D:\专业\ideajava\CSDN\123.txt ENTRY_CREATE
D:\专业\ideajava\CSDN\create ENTRY_CREATE
D:\专业\ideajava\CSDN\234.txt ENTRY_MODIFY
D:\专业\ideajava\CSDN\234.txt ENTRY_DELETE
D:\专业\ideajava\CSDN\create ENTRY_MODIFY
* */
注意:
- WatchService监听在系统支持的情况下采用事件驱动机制,可降档为扫描式机制。
- 事件发生后需使用reset()方法重置WatchKey对象,否则事件所属的目录的改动通知只会发生一次。