`
callwangxiang
  • 浏览: 3329 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

通过Java SE 7自带的监控服务(WatchService API)实现类似.NET FileWatcher的功能

阅读更多

《模式——工程化实现及扩展》(设计模式Java 版)

 

 

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

 

0
3
分享到:
评论

相关推荐

    Java 实现 ADO.NET DataTable

    在Java中,没有直接对应的类可以完全等同于ADO.NET的DataTable,但我们可以使用Java的数据结构和API来实现类似的功能。下面将详细介绍如何在Java中构建一个类似的数据表对象。 1. **Java集合框架**: Java提供了...

    java 文件实时监听watchService

    在Java 7及以上版本中引入,它提供了一种有效的方式来进行实时监控,而无需频繁轮询文件系统,这极大地提高了效率,特别是在配置动态修改时,可以避免不必要的服务器重启。 `WatchService`的工作原理是通过注册对...

    asp.net通过WebService调用Java接口全过程

    ASP.NET调用Java接口主要涉及的是跨平台的通信技术,其中关键步骤是通过WebService作为中间桥梁来实现。这里,我们详细解析整个过程: 1. **部署Java WebService**: - 使用Tomcat这样的应用服务器部署Java ...

    Java SE 8 API (JDK 1.8 API)

    官方JDK 1.8 英文版编译,Java SE 8 API (JDK 1.8 API)

    JAVA_API1.6文档(中文)

    java.net 为实现网络应用程序提供类。 java.nio 定义作为数据容器的缓冲区,并提供其他 NIO 包的概述。 java.nio.channels 定义了各种通道,这些通道表示到能够执行 I/O 操作的实体(如文件和套接字)的连接;定义...

    用java调用.net接口的方法

    总的来说,调用.NET接口在Java中可以通过标准Web服务方式或RESTful接口实现,选择哪种方法取决于.NET接口的具体设计和项目需求。熟悉这些技术对于提高跨平台开发的效率至关重要。记得在实际应用中,一定要确保兼容性...

    FileMonitor 基于jdk7文件监控WatchService

    《基于JDK7的FileMonitor:精简版文件监控服务详解》 在Java开发中,对文件系统的实时监控是一项常用且重要的任务。JDK7引入了`WatchService`接口,为开发者提供了一种监听文件系统变化的能力。然而,`WatchService...

    VB.NET转JAVA工具

    4. **事件处理**:VB.NET的事件处理模型基于委托和事件,而在Java中通常通过接口和监听器实现。 5. **异常处理**:VB.NET的Try...Catch...Finally需要转换为Java的try...catch...finally。 6. **LINQ转换**:如果VB...

    C# .net 使用Java公钥实现RSA加密

    C# .net 使用Java公钥实现RSA加密

    .net 与Java间RSA加密的转换

    `Base64Helper.java`可能包含与`StringUtils.java`类似的功能,专注于Base64编码和解码。在.NET和Java中进行加密操作时,通常会先将密钥和加密后的数据进行Base64编码,以便于文本形式的传输。 在.NET和Java之间...

    基于java的文件监控程序设计与实现.zip

    9. **第三方库**:虽然Java自带的WatchService API已经足够使用,但有些第三方库如Apache Commons IO、JNotify、FileWatcher等提供了更高级的功能和更好的跨平台兼容性,可以根据项目需求选择使用。 10. **应用场景...

    java和.net的socket通信

    在Java中,Socket类位于`java.net`包下,而在.NET中,Socket类位于`System.Net.Sockets`命名空间内。 2. **TCP连接**:Java和.NET的Socket通信通常基于TCP(传输控制协议),这是一种面向连接的、可靠的传输协议,...

    Java RSA加密 与.net 的密匙转换完整版,java类

    在实际应用中,这种转换对于跨平台的移动应用或者Web服务特别有用,比如Java服务器端和.NET客户端之间的通信。通过这个转换工具,你可以确保数据在不同环境下的安全性,同时避免了因密钥格式不匹配导致的通信障碍。 ...

    java调用.net发布的webservice(asmx)

    2. 使用WSDL2Java工具:通过.NET ASMX Web服务的WSDL地址,运行CXF的WSDL2Java命令生成Java客户端代码。这将生成一个服务接口和服务实现类,其中包含了调用Web服务的方法。 3. 编写Java代码:实例化生成的服务实现...

    java flash上传插件,动态调用.net的webapi

    本篇文章将探讨如何在Java环境中利用Flash上传插件实现对.NET WebAPI的动态调用,以便进行批量文件上传。 首先,Java Flash上传插件是解决跨语言、跨平台文件上传的一种解决方案。Flash作为一个曾经流行的客户端...

    JAVA API官方文档 中文版

    2. **网络编程**:`java.net`包提供了网络通信的支持,包括Socket和ServerSocket类,用于实现客户端和服务器端的连接。 3. **多线程**:`java.concurrent`包提供了高级并发工具,如ExecutorService、Semaphore、...

    ASP.NET WEB API 程序设计

    《ASP.NET Web API设计》依托ASP.NET Web API阐述API设计与开发的通用技术,是一本全面介绍如何构建真实可演化API的实践指南。本书共分三部分。第一部分介绍Web/HTTP和API开发的基础知识,介绍ASP.NET Web API,为...

    java实现,简单文件监控

    在Java编程语言中,实现对本地文件的简单监控是一项实用的技术,这可以帮助开发者在文件系统中检测到诸如移动、复制和粘贴等操作。本文将深入探讨如何利用Java的文件I/O API和事件监听机制来达成这个目标。 首先,...

    JAVA与.NET的相互调用通过Web服务实现相互调用.doc

    本文将详细介绍如何通过Web服务实现Java与.NET之间的相互调用。 Web服务作为一种标准化的通信机制,使得不同语言和平台的应用程序能够相互通信。其核心组成部分包括XML、XSD、SOAP和WSDL。 1. XML(可扩展标记语言...

    java项目jar包转dll文件.net引用

    在.NET环境中,有时候我们需要将Java项目中的功能引入到C#项目中使用,这时就需要将Java的jar包转换为.NET能够识别的dll文件。这个过程主要涉及到Java与.NET之间的互操作性,具体步骤如下: 首先,我们需要了解Java...

Global site tag (gtag.js) - Google Analytics