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的功能的更多相关文章

  1. k8s1.11.0安装、一个master、一个node、查看node名称是主机名、node是扩容进来的、带cadvisor监控服务

    一个master.一个node.查看node节点是主机名 # 安装顺序:先在test1 上安装完必要组件后,就开始在 test2 上单独安装node组件,实现node功能,再返回来配置test1加入集 ...

  2. k8s1.11.0安装、一个master、一个node、查看node名称是ip、node是扩容进来的、带cadvisor监控服务

    一个master.一个node.查看node节点是ip # 安装顺序:先在test1 上安装完必要组件后,就开始在 test2 上单独安装node组件,实现node功能,再返回来配置test1加入集群 ...

  3. Java SE 6 新特性: 对脚本语言的支持

    2006 年底,Sun 公司发布了 Java Standard Edition 6(Java SE 6)的最终正式版,代号 Mustang(野马).跟 Tiger(Java SE 5)相比,Musta ...

  4. Java SE 9 新增特性

    Java SE 9 新增特性 作者:Grey 原文地址: Java SE 9 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new_ ...

  5. Java高级应用(一个)-文件夹监控服务

    最近.在研究一些比较成熟的框架.他们还发现,他们中的一些相当不错的文章.现在,对于一些在你们中间一个简单的翻译(版的英文文章,非常有帮助). 译:原文链接 你有没有发现,当你编辑一个文件.同一时候使用 ...

  6. 【转】使用JDK自带jvisualvm监控tomcat

    转载地址: http://my.oschina.net/kone/blog/157239 jdk自带有个jvisualvm工具.该工具是用来监控java运行程序的cpu.内存.线程等的使用情况.并且使 ...

  7. 使用JDK自带jvisualvm监控tomcat

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  8. Eclipse启动时报需要安装"Java SE 6 Runtime"致无法启动解决方案

    今天心血来潮,把MBP升级到了osx mavericks,然后启动了闲置好久的eclipse,启动时居然报错了: 若要打开Eclipse.app,您需要Java SE 6 runtime,您想现在安装 ...

  9. java se 6在solaris的可观察性特征分析

        java平台标准版(java se)6,代码名为"mustang",是最新的java se发行版本(正在开发中).java se 6源码和二进制代码都可以在www.java ...

随机推荐

  1. Python的设计模式学习

    1.工厂模式 #encoding=utf-8 __author__ = 'kevinlu1010@qq.com' class ADD(): def getResult(self,*args): ret ...

  2. hdu 2079 选课时间

    hdu 2079 选课时间 题意:选的学分总和为n,并且学分为a的课有b种,总共有K(1<=k<=8)种学分不同的课,并且要选的学分最多为40:问选课方案有多少种?(学分相同的课即认为相同 ...

  3. JQ+AJAX实现多级联动

    利用JQ与AJAX实现三级联动实现的效果: 当前两级改变时,后边一级或两级都会改变: 使用的数据库: html代码: <!doctype html> <html lang=" ...

  4. JSON和JSONP,也许你会豁然开朗,含jQuery用例

    前言: 说到AJAX就会不可避免的面临两个问题,第一个是AJAX以何种格式来交换数据?第二个是跨域的需求如何解决?这两个问题目前都有不同的解决方案,比如数据可以用自定义字符串或者用XML来描述,跨域可 ...

  5. noj [1475] Bachelor (找1的个数)

    http://ac.nbutoj.com/Problem/view.xhtml?id=1475 [1475] Bachelor 时间限制: 1000 ms 内存限制: 65535 K 问题描述 炎热的 ...

  6. 应该知道的25个非常有用的CSS技巧

    在我们的前端CSS编码当中,经常要设置特殊的字体效果,边框圆角等等,还要考虑兼 容性的问题, CSS网页布局,说难,其实很简单.说它容易,往往有很多问题困扰着新 手,在中介绍了非常多的技巧,这些小技巧 ...

  7. Portal技术综述

    从上世纪八十年代起,随着个人计算机(PC)的发展,企事业单位逐步建立起计算机应用系统来处理传统事务.从简单的单机应用逐步发展到局域网系统,进而建立跨地区垮国家的广域网系统.从单纯的以科学计算和数据管理 ...

  8. unity 嵌入 百度分享 与 游戏内购物 iap

    原地址:http://blog.csdn.net/u012085988/article/details/18268869 最近老板让在unity项目里实现分享与内购功能,还要ios和android两个 ...

  9. FZU 2140 Forever 0.5

     Problem 2140 Forever 0.5 Accept: 36    Submit: 113    Special JudgeTime Limit: 1000 mSec    Memory ...

  10. CDQ分治题目小结

    CDQ分治属于比较特殊的一类分治,许多问题转化为这类分治的时候,时空方面都会有很大节省,而且写起来没有这么麻烦. 这类分治的特殊性在于分治的左右两部分的合并,作用两部分在合并的时候作用是不同的,比如, ...