dirwatcher java_(转)通过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定义事件参数对象

packagemarvellousworks.practicalpattern.concept.unittest;importjava.nio.file.WatchEvent.Kind;/*** 文件系统事件类型

*@authorwangxiang

**/

public final classFileSystemEventArgs {private finalString fileName;private final Kind>kind;public FileSystemEventArgs(String fileName, Kind>kind){this.fileName =fileName;this.kind =kind;

}/*** 文件的路径*/

public String getFileName(){returnfileName;}/*** 操作类型:变更、创建、删除*/@SuppressWarnings("rawtypes")public Kind getKind(){returnkind;}

}

2、定义DirectoryWatcher,用于监控某个文件夹,至于如何扩展FileWatcher则可以在这个基础上通过限定文件名称和操作类型的方式扩展

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;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

*

*@authorwangxiang

**/

public class DirectoryWatcher extendsObservable{privateWatchService watcher;privatePath path;privateWatchKey key;private Executor executor =Executors.newSingleThreadExecutor();

FutureTask task = new FutureTask(new Callable(){public Integer call() throwsInterruptedException{

processEvents();return Integer.valueOf(0);}});

@SuppressWarnings("unchecked")static WatchEvent cast(WatchEvent>event) {return (WatchEvent) event;

}public DirectoryWatcher(String dir) throwsIOException {

watcher=FileSystems.getDefault().newWatchService();

path=Paths.get(dir);//监控目录内文件的更新、创建和删除事件

key =path.register(watcher, ENTRY_MODIFY, ENTRY_CREATE, ENTRY_DELETE);

}/*** 启动监控过程*/

public voidexecute(){//通过线程池启动一个额外的线程加载Watching过程

executor.execute(task);

}/*** 关闭后的对象无法重新启动

*@throwsIOException*/

public void shutdown() 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 handled

if (kind ==OVERFLOW) {continue;

}//Context for directory entry event is the file name of entry

WatchEvent ev =cast(event);

Path name=ev.context();

notifiy(name.getFileName().toString(), kind);

}//为监控下一个通知做准备

key.reset();

}

}/*** 通知外部各个Observer目录有新的事件更新*/

void notifiy(String fileName, Kind>kind){//标注目录已经被做了更改

setChanged();//主动通知各个观察者目标对象状态的变更//这里采用的是观察者模式的“推”方式

notifyObservers(newFileSystemEventArgs(fileName, kind));

}

}

3、单元测试

packagecom.ieslab.web.tool;import staticjava.nio.file.StandardWatchEventKinds.ENTRY_CREATE;importjava.io.File;importjava.io.IOException;importjava.util.ArrayList;importjava.util.List;importjava.util.Observable;importjava.util.Observer;importorg.junit.Assert;importorg.junit.Test;public classDirectoryWatcherFixture {private static final String DIR_PATH =System.getProperty("user.dir");private static final File DIR = newFile(DIR_PATH);private static final String SUFFIX = ".txt";private static final String PREFIX = "test";private static final int ADD_TIMES = 3;/*** 观察者

*@authorwangxiang

**/

public class Logger implementsObserver{

@Overridepublic voidupdate(Observable observable, Object eventArgs) {

FileSystemEventArgs args=(FileSystemEventArgs) eventArgs;

System.out.printf("%s has been %s\n", args.getFileName(), args.getKind());

Assert.assertTrue(args.getFileName().startsWith(PREFIX));

Assert.assertEquals(ENTRY_CREATE, args.getKind());

}

}

@Testpublic void testWatchFile() throwsIOException, InterruptedException{

DirectoryWatcher watcher= newDirectoryWatcher(DIR_PATH);

Logger l1= newLogger();

watcher.addObserver(l1);

watcher.execute();//创建一系列临时文件

List files = new ArrayList<>();for(int i=0; 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值