Java SE 7 Tutorial中增加了一个监控目录变更情况的示例,用于介绍其新发布的WatchService API。

 

但对于用惯了.NET FileWatcher的用户而言,如果用于项目我认为它有两个欠缺:

1、应该提供一个独立线程后台运行机制,让这个监控过程自己在后台转,不影响前端处理

2、 Java不像.NET有内置的源生事件机制,不过可以借助它内置的Observer/Observable对象用观察者模式实现准事件

 

下面是把Java SE Tutorial示例中无关内容删除,补充上述两个扩展后的实现,因为这个API比较新,也希望能和大家多多探讨:

 

1、参考.NET定义事件参数对象



Java StopWatch 使用_测试

package marvellousworks.practicalpattern.concept.unittest;

import java.nio.file.WatchEvent.Kind;

/**
 * 文件系统事件类型
 * @author wangxiang
 *
 */
publicfinalclass FileSystemEventArgs {
    privatefinal String fileName;
    privatefinal<?> kind;
    
    public<?> kind){
        this.fileName = fileName;
        this.kind = kind;
    }
    
    /**
     * 文件的路径
     */
    publicreturn fileName;}
    
    /**
     * 操作类型:变更、创建、删除
     */
    @SuppressWarnings("rawtypes")
    publicreturn kind;}
}

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

 



Java StopWatch 使用_测试



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;

importstatic*;

/**
 * 监控一个目录内文件的更新、创建和删除事件(不包括子目录)
 * 
 * 对于http://download.oracle.com/javase/tutorial/essential/io/notification.html进行了改造
 * 使其更接近.NET的DirectoryWatcher使用习惯
 * 
 * 由于java没有类似.NET源生的事件机制
 * 因此实现上采用了Java SE自带的Observer/Observable对象对外抛出“假”事件
 * 
 * 适于Java SE 7
 * 
 * @author wangxiang
 *
 */
publicclassextendsObservable{

    private WatchService watcher;
    private Path path;
    private WatchKey key;
    private Executor executor = Executors.newSingleThreadExecutor();
    
    FutureTask<Integer>=new<Integer>(
            new<Integer>(){
                publicthrows InterruptedException{
                    processEvents();
                    return0);}});

    @SuppressWarnings("unchecked")
    static<T><T><?> event) {
        return<T>) event;
    }

    publicthrows IOException {
        watcher = FileSystems.getDefault().newWatchService();
        path = Paths.get(dir);
        //
= path.register(watcher, ENTRY_MODIFY, ENTRY_CREATE, ENTRY_DELETE);
    }

    /**
     * 启动监控过程
     */
    publicvoid execute(){
        //
        executor.execute(task);        
    }
    
    /**
     * 关闭后的对象无法重新启动
     * @throws IOException
     */
    publicvoidthrows IOException {
        watcher.close();
        executor =null;
    }

    /**
     * 监控文件系统事件
     */
    void processEvents() {
        whiletrue) {
            //
            WatchKey signal;
            try {
                signal = watcher.take();
            } catch (InterruptedException x) {
                return;
            }

            for<?> event : signal.pollEvents()) {
                Kind<?>= event.kind();

                //
if== OVERFLOW) {
                    continue;
                }

                //
<Path>= 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));    }}



Java StopWatch 使用_测试



 

 3、单元测试



Java StopWatch 使用_测试



package marvellousworks.practicalpattern.concept.unittest;

importstatic*;

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

publicclass DirectoryWatcherFixture {

    privatestaticfinal=System.getProperty("user.dir"); 
    privatestaticfinal=new File(DIR_PATH);
    privatestaticfinal=".txt";
    privatestaticfinal="test";
    privatestaticfinalint=3;

    /**
     * 观察者
     * @author wangxiang
     *
     */
    publicclassimplements Observer{
        @Override
        publicvoid 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
    publicvoidthrows IOException, InterruptedException{
        DirectoryWatcher watcher =new DirectoryWatcher(DIR_PATH);
        Logger l1 =new Logger();
        watcher.addObserver(l1);
        watcher.execute();
        
        //
<String>=new<>();
        for(int=0; i<ADD_TIMES; i++){
            files.add(File.createTempFile(PREFIX, SUFFIX, DIR).toString());
        }
        
        //
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