packagemarvellousworks.practicalpattern.concept.unittest;importjava.io.IOException;importjava.nio.file.FileSystems;importjava.nio.file.Path;importjava.nio.file.Paths;importjava.nio.file.WatchEvent;importjava.nio.file.WatchEvent.Kind;importjava.nio.file.WatchKey;importjava.nio.file.WatchService;importjava.util.Observable;importjava.util.concurrent.Callable;importjava.util.concurrent.Executor;importjava.util.concurrent.Executors;importjava.util.concurrent.FutureTask;importstaticjava.nio.file.StandardWatchEventKinds.*;/*** 监控一个目录内文件的更新、创建和删除事件(不包括子目录)
*
* 对于http://download.oracle.com/javase/tutorial/essential/io/notification.html进行了改造
* 使其更接近.NET的DirectoryWatcher使用习惯
*
* 由于java没有类似.NET源生的事件机制
* 因此实现上采用了Java SE自带的Observer/Observable对象对外抛出“假”事件
*
* 适于Java SE 7
*
*@authorwangxiang
**/publicclassDirectoryWatcherextendsObservable{privateWatchService watcher;privatePath path;privateWatchKey key;privateExecutor executor=Executors.newSingleThreadExecutor();
FutureTasktask=newFutureTask(newCallable(){publicInteger call()throwsInterruptedException{
processEvents();returnInteger.valueOf(0);}});
@SuppressWarnings("unchecked")staticWatchEventcast(WatchEvent>event) {return(WatchEvent) event;
}publicDirectoryWatcher(String dir)throwsIOException {
watcher=FileSystems.getDefault().newWatchService();
path=Paths.get(dir);//监控目录内文件的更新、创建和删除事件key=path.register(watcher, ENTRY_MODIFY, ENTRY_CREATE, ENTRY_DELETE);
}/*** 启动监控过程*/publicvoidexecute(){//通过线程池启动一个额外的线程加载Watching过程executor.execute(task);
}/*** 关闭后的对象无法重新启动
*@throwsIOException*/publicvoidshutdown()throwsIOException {
watcher.close();
executor=null;
}/*** 监控文件系统事件*/voidprocessEvents() {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 handledif(kind==OVERFLOW) {continue;
}//Context for directory entry event is the file name of entryWatchEventev=cast(event);
Path name=ev.context();notifiy(name.getFileName().toString(), kind);}//为监控下一个通知做准备key.reset();
}
}/*** 通知外部各个Observer目录有新的事件更新*/voidnotifiy(String fileName, Kind>kind){//标注目录已经被做了更改setChanged();//主动通知各个观察者目标对象状态的变更//这里采用的是观察者模式的“推”方式notifyObservers(newFileSystemEventArgs(fileName, kind));
}
}