彩票走势图

通过Java SE 7监控服务实现类似.NET FileWatcher的功能

转帖|其它|编辑:郝浩|2011-08-04 13:59:31.000|阅读 593 次

概述:Java SE 7 Tutorial中增加了一个监控目录变更情况的示例,用于介绍其新发布的WatchService API。 下面是把Java SE Tutorial示例中无关内容删除,补充上述两个扩展后的实现,因为这个API比较新,也希望能和大家多多探讨。

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

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

/**
  * 监控一个目录内文件的更新、创建和删除事件(不包括子目录)
  * 
  * 对于//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

标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn

文章转载自:网络转载

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP