通过Java SE 7自带的监控服务(WatchService API)实现类似.NET FileWatcher的功能
Java SE 7 Tutorial中增加了一个监控目录变更情况的示例,用于介绍其新发布的WatchService API。
但对于用惯了.NET FileWatcher的用户而言,如果用于项目我认为它有两个欠缺:
1、应该提供一个独立线程后台运行机制,让这个监控过程自己在后台转,不影响前端处理
2、 Java不像.NET有内置的源生事件机制,不过可以借助它内置的Observer/Observable对象用观察者模式实现准事件
下面是把Java SE Tutorial示例中无关内容删除,补充上述两个扩展后的实现,因为这个API比较新,也希望能和大家多多探讨:
1、参考.NET定义事件参数对象
package marvellousworks.practicalpattern.concept.unittest; import java.nio.file.WatchEvent.Kind; /**
* 文件系统事件类型
* @author wangxiang
*
*/
public final class FileSystemEventArgs {
private final String fileName;
private final Kind<?> kind;
public FileSystemEventArgs(String fileName, Kind<?> kind){
this.fileName = fileName;
this.kind = kind;
}
/**
* 文件的路径
*/
public String getFileName(){return fileName;}
/**
* 操作类型:变更、创建、删除
*/
@SuppressWarnings("rawtypes")
public Kind getKind(){return kind;}
}
2、定义DirectoryWatcher,用于监控某个文件夹,至于如何扩展FileWatcher则可以在这个基础上通过限定文件名称和操作类型的方式扩展
package marvellousworks.practicalpattern.concept.unittest; import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.Observable;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask; import static java.nio.file.StandardWatchEventKinds.*; /**
* 监控一个目录内文件的更新、创建和删除事件(不包括子目录)
*
* 对于http://download.oracle.com/javase/tutorial/essential/io/notification.html进行了改造
* 使其更接近.NET的DirectoryWatcher使用习惯
*
* 由于java没有类似.NET源生的事件机制
* 因此实现上采用了Java SE自带的Observer/Observable对象对外抛出“假”事件
*
* 适于Java SE 7
*
* @author wangxiang
*
*/
public class DirectoryWatcher extends Observable{ private WatchService watcher;
private Path path;
private WatchKey key;
private Executor executor = Executors.newSingleThreadExecutor();
FutureTask<Integer> task = new FutureTask<Integer>(
new Callable<Integer>(){
public Integer call() throws InterruptedException{
processEvents();
return Integer.valueOf(0);}}); @SuppressWarnings("unchecked")
static <T> WatchEvent<T> cast(WatchEvent<?> event) {
return (WatchEvent<T>) event;
} public DirectoryWatcher(String dir) throws IOException {
watcher = FileSystems.getDefault().newWatchService();
path = Paths.get(dir);
// 监控目录内文件的更新、创建和删除事件
key = path.register(watcher, ENTRY_MODIFY, ENTRY_CREATE, ENTRY_DELETE);
} /**
* 启动监控过程
*/
public void execute(){
// 通过线程池启动一个额外的线程加载Watching过程
executor.execute(task);
}
/**
* 关闭后的对象无法重新启动
* @throws IOException
*/
public void shutdown() throws IOException {
watcher.close();
executor = null;
} /**
* 监控文件系统事件
*/
void processEvents() {
while (true) {
// 等待直到获得事件信号
WatchKey signal;
try {
signal = watcher.take();
} catch (InterruptedException x) {
return;
} for (WatchEvent<?> event : signal.pollEvents()) {
Kind<?> kind = event.kind(); // TBD - provide example of how OVERFLOW event is handled
if (kind == OVERFLOW) {
continue;
} // Context for directory entry event is the file name of entry
WatchEvent<Path> ev = cast(event);
Path name = ev.context(); notifiy(name.getFileName().toString(), kind); } // 为监控下一个通知做准备 key.reset(); } } /** * 通知外部各个Observer目录有新的事件更新 */ void notifiy(String fileName, Kind<?> kind){ // 标注目录已经被做了更改 setChanged(); // 主动通知各个观察者目标对象状态的变更 // 这里采用的是观察者模式的“推”方式 notifyObservers(new FileSystemEventArgs(fileName, kind)); }}
3、单元测试
package marvellousworks.practicalpattern.concept.unittest; import static org.junit.Assert.*; import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer; import org.junit.Test;
import static java.nio.file.StandardWatchEventKinds.*; public class DirectoryWatcherFixture { private static final String DIR_PATH =System.getProperty("user.dir");
private static final File DIR = new File(DIR_PATH);
private static final String SUFFIX = ".txt";
private static final String PREFIX = "test";
private static final int ADD_TIMES = 3; /**
* 观察者
* @author wangxiang
*
*/
public class Logger implements Observer{
@Override
public void update(Observable observable, Object eventArgs) {
FileSystemEventArgs args = (FileSystemEventArgs) eventArgs;
System.out.printf("%s has been %s\n", args.getFileName(), args.getKind());
assertTrue(args.getFileName().startsWith(PREFIX));
assertEquals(ENTRY_CREATE, args.getKind());
}
}
@Test
public void testWatchFile() throws IOException, InterruptedException{
DirectoryWatcher watcher = new DirectoryWatcher(DIR_PATH);
Logger l1 = new Logger();
watcher.addObserver(l1);
watcher.execute();
// 创建一系列临时文件
List<String> files = new ArrayList<>();
for(int i=0; i<ADD_TIMES; i++){
files.add(File.createTempFile(PREFIX, SUFFIX, DIR).toString());
}
// 延迟等待后台任务的执行
Thread.sleep(4000);
watcher.shutdown();
System.out.println("finished");
}
}
Console窗口显示的测试内容
test5769907807190550725.txt has been ENTRY_CREATE
test4657672246246330348.txt has been ENTRY_CREATE
test1823102943601166149.txt has been ENTRY_CREATE
finished
通过Java SE 7自带的监控服务(WatchService API)实现类似.NET FileWatcher的功能的更多相关文章
- k8s1.11.0安装、一个master、一个node、查看node名称是主机名、node是扩容进来的、带cadvisor监控服务
一个master.一个node.查看node节点是主机名 # 安装顺序:先在test1 上安装完必要组件后,就开始在 test2 上单独安装node组件,实现node功能,再返回来配置test1加入集 ...
- k8s1.11.0安装、一个master、一个node、查看node名称是ip、node是扩容进来的、带cadvisor监控服务
一个master.一个node.查看node节点是ip # 安装顺序:先在test1 上安装完必要组件后,就开始在 test2 上单独安装node组件,实现node功能,再返回来配置test1加入集群 ...
- Java SE 6 新特性: 对脚本语言的支持
2006 年底,Sun 公司发布了 Java Standard Edition 6(Java SE 6)的最终正式版,代号 Mustang(野马).跟 Tiger(Java SE 5)相比,Musta ...
- Java SE 9 新增特性
Java SE 9 新增特性 作者:Grey 原文地址: Java SE 9 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new_ ...
- Java高级应用(一个)-文件夹监控服务
最近.在研究一些比较成熟的框架.他们还发现,他们中的一些相当不错的文章.现在,对于一些在你们中间一个简单的翻译(版的英文文章,非常有帮助). 译:原文链接 你有没有发现,当你编辑一个文件.同一时候使用 ...
- 【转】使用JDK自带jvisualvm监控tomcat
转载地址: http://my.oschina.net/kone/blog/157239 jdk自带有个jvisualvm工具.该工具是用来监控java运行程序的cpu.内存.线程等的使用情况.并且使 ...
- 使用JDK自带jvisualvm监控tomcat
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- Eclipse启动时报需要安装"Java SE 6 Runtime"致无法启动解决方案
今天心血来潮,把MBP升级到了osx mavericks,然后启动了闲置好久的eclipse,启动时居然报错了: 若要打开Eclipse.app,您需要Java SE 6 runtime,您想现在安装 ...
- java se 6在solaris的可观察性特征分析
java平台标准版(java se)6,代码名为"mustang",是最新的java se发行版本(正在开发中).java se 6源码和二进制代码都可以在www.java ...
随机推荐
- 通过 ANE(Adobe Native Extension) 启动Andriod服务 推送消息(二)
着手改造之前,有兴趣可以阅读下官方文档:http://help.adobe.com/zh_CN/air/extensions/index.html 新建工程 NavService 并创建包 nav.w ...
- OpenCV2学习笔记05:矩阵翻转
对图像进行翻转或旋转可以使用cv::flip()函数,可以实现将一个二维矩阵沿X轴.Y轴或者同时沿XY轴翻转.函数原型如下: C++: void flip(InputArray src, Output ...
- lsof作用
lsof 卸载移动存储时经常提示device busy,也可能误删了一个正在打开的文件.... 这时候可以试试lsof lsof简介 lsof(list open files)是一个列出当前系统打 ...
- JSP Ajax
html代码: <!DOCTYPE html> <html> <script> function display() { var div=document.getE ...
- 伪装隐藏Nginx,PHP版本号提升服务器安全性
可能有时候我们看某些站点想知道别人在使用什么版本的web服务器之类的信息时,却发现并未显示版本号,甚至连WEB服务器都有变化,可以通过以下 方法来隐藏Nginx.PHP的版本号信息,来提升一定的安全性 ...
- Python设计模式——设计原则
1.单一职责原则:每个类都只有一个职责,修改一个类的理由只有一个 2.开放-封闭远程(OCP):开放是指可拓展性好,封闭是指一旦一个类写好了,就尽量不要修改里面的代码,通过拓展(继承,重写等)来使旧的 ...
- PL/SQL — BULK COLLECT用法
BULK COLLECT 子句会批量检索结果,即一次性将结果集绑定到一个集合变量中,并从SQL引擎发送到PL/SQL引擎.通常可以在SELECT INTO.FETCH INTO以及RETURNING ...
- 如何实现一个malloc函数
一.概述 1.malloc简介 函数所在头文件:<stdlib.h> 函数原型是:void *malloc (size_t n) 函数功能:在内存的动态存储区中分配一个长度为size的连续 ...
- 【springmvc Request】 springmvc请求接收参数的几种方法
通过@PathVariabl注解获取路径中传递参数 转载请注明出处:springmvc请求接收参数的几种方法 代码下载地址:http://www.zuida@ima@com/share/1751862 ...
- 树莓派2 安装mono3.0运行mvc4
sudo apt-get updatesudo apt-get upgradesudo apt-get mono-completewget -c http://www.linuxdot.net/dow ...