- 浏览: 141861 次
- 性别:
- 来自: 深圳
最新评论
-
freesea:
不错,还没注意java 7已经增加了这么多类了
[NIO.2] 第十篇 NIO.2 中的文件属性 -
SpringJava:
有个问题,想请教一下楼主:在代码中经常看到try catch语 ...
[NIO.2] 第二十九篇 删除、复制、移动目录和文件 -
xiaohu7924:
高
什么是 Java ? -
jiiming:
这种方法可以借鉴
[Java EE 7] Servlet 异步支持 -
cucaracha:
jahu 写道有中文文档没有啊。请留意我的博客:http:// ...
Java EE 7 技术一览
要实现监控服务需要有几个步骤。在本文中,你将会看到实现监控服务的主要步骤,并且开发监控目录创建、删除和修改的应用。每个步骤都会有代码和实例进行讲解,文章的最后将会把所有步骤合在一起,编写一个完整的应用。
创建 WatchService
最开始,需要创建 WatchService 用于监控文件系统。可以调用 FileSystem.newWatchService() 方法来创建这个对象:
现在我们有了 WatchService 对象。
注册监控对象
每个被监控对象都需要注册后才能被监控。任何实现 Watchable 接口的对象都可以被注册。在我们的例子中,将会注册目录的 Path 对象。除了监控对象外,监控服务还需要设置需要监控的事件类型。所有支持的监控事件类型都映射到 StandardWatchEventKinds 类中的 Kind<Path> 类型的常量上。
Path 类实现了 Watchable 接口,因此可以调用 Watchable.register() 方法。这个方法有两个重载方法,第一个重载方法接受两个参数,第一个参数是 WatchService 对象,第二个是可变长参数,用于设置监控哪些事件。第二个重载方法除了这两个参数外,还接受一个参数,用于设置目录如何注册的限制符,但是目前 NIO.2 还没有提供标准限制符。
下面的代码将会注册 C:\rafaelnadal 目录,并监控创建、删除和修改事件:
你将会收到注册目录的 WatchKey 对象,这是使用 WatchService 注册后被监控对象的唯一标识。你可以选择是否保留这个引用。在事件被触发后,WatchService 将会返回相关的 WatchKey。具体内容参看下文。
等待传入事件
等待传入事件需要一个无限循环。当事件被触发,监控服务将会把 WatchKey 放入监控队列中。无限循环可能是下面的类型:
或者可能是下面的类型:
获取 WatchKey
从队列中获取 WatchKey 可以调用 WatchService 中的三个方法其中一个。三个方法功能都是获取队列中的下一个 Key 并且将它从队列中删除。不同的地方是如果没有可用的 Key 的处理方式。下面看看这三个方法:
下面的代码将演示如何在无限循环中调用这三个方法:
记住,每个 key 都有自己的状态,分别是就绪(ready),信号(signaled),无效(invalid):
注意,WatchKey 是线程安全的。
获取事件
当一个 key 处于信号状态,表示上面有一个或多个事件需要关注。可以调用 WatchKey.pollEvents() 方法获取并删除全部事件。这个方法不需要参数,调用后返回包含事件的 List 对象,List 中的类型是 WatchEvent<T>,它表示注册到 WatchService 中的对象上的事件。
如果没有获取到事件,pollEvents() 并不会等待,而是直接返回一个空的 List。
下面的代码将会从 key 获取事件,并遍历所有事件:
WatchEvent 是不可变对象并且是线程安全的。
获取事件属性
WatchEvent<T> 中保存了事件的属性,可以调用 WatchEvent.kind() 方法获取事件类型,这个方法将返回 Kind<T> 类型的对象。
下面的代码演示了如何获取事件属性:
除了事件类型,还可以调用 WatchEvent.count() 方法获取事件被观察次数(重复事件)。返回值是 int:
获取事件的文件名
当文件的删除、创建或修改事件被触发后,我们可以通过事件的上下文获取文件名称(文件名存储在事件上下文中)。可以调用 WatchEvent.context() 方法来实现这个功能:
将 Key 重置为就绪状态
如果 key 处于信号状态,那么将一直保持,直到调用 reset() 将其重置为就绪状态。如果 reset() 方法返回 true,表示 key 有效并且已经被重置,返回 false 表示重置失败,原因有可能是 key 不再有效。有的时候,如果 key 不再有效的话,我们需要跳出循环,例如,只有一个 key 的时候,没有必要再继续留在无限循环中,如下代码所示:
注意,如果忘记调用 reset() 或者调用 reset() 失败,那么 Key 将不再接收任何事件!
关闭 WatchService
当线程结束或监控服务关闭的时候,需要显式的调用 WatchService.close() 方法,或者将 WatchService 放入 try 语句块中:
当 WatchService 关闭后,当前的操作将会取消并且失效。如果服务关闭,任何操作都会抛出 ClosedWatchServiceException 异常。如果服务已经关闭,再调用这个方法不会有任何效果。
综合运用
下面的代码将会监控 C:\rafaelnadal 目录的创建、删除和修改事件。并且打印出事件类型和文件名。当程序运行后,可以手动创建、删除和修改此目录下的文件或目录,看看程序运行的效果。注意,此程序只对 C:\rafaelnadal 目录实现监控,其下的子目录并没有被监控。
注意,这段代码使用了无限循环,因此需要手动结束,或者自行编写一个结束机制。
文章来源:http://www.aptusource.org/2014/04/nio-2-implementing-a-watch-service/
创建 WatchService
最开始,需要创建 WatchService 用于监控文件系统。可以调用 FileSystem.newWatchService() 方法来创建这个对象:
WatchService watchService = FileSystems.getDefault().newWatchService();
现在我们有了 WatchService 对象。
注册监控对象
每个被监控对象都需要注册后才能被监控。任何实现 Watchable 接口的对象都可以被注册。在我们的例子中,将会注册目录的 Path 对象。除了监控对象外,监控服务还需要设置需要监控的事件类型。所有支持的监控事件类型都映射到 StandardWatchEventKinds 类中的 Kind<Path> 类型的常量上。
- StandardWatchEventKinds.ENTRY_CREATE:创建目录实体。当目录中的文件重命名和移动文件到此目录时,也会触发 ENTRY_CREATE 事件。
- StandardWatchEventKinds.ENTRY_DELETE:删除目录实体。当目录中的文件重命名和移动文件出此目录时,也会触发 ENTRY_DELETE 事件。
- StandardWatchEventKinds.ENTRY_MODIFY:修改目录实体。修改事件在具有平台相关性,但是无论什么平台,只要修改了文件内容,就会触发这个事件。在有的平台上,改变文件属性也会触发这个事件。
- StandardWatchEventKinds.OVERFLOW:表示事件可能丢失或遗弃。在注册的时候不需要监听这个事件。
Path 类实现了 Watchable 接口,因此可以调用 Watchable.register() 方法。这个方法有两个重载方法,第一个重载方法接受两个参数,第一个参数是 WatchService 对象,第二个是可变长参数,用于设置监控哪些事件。第二个重载方法除了这两个参数外,还接受一个参数,用于设置目录如何注册的限制符,但是目前 NIO.2 还没有提供标准限制符。
下面的代码将会注册 C:\rafaelnadal 目录,并监控创建、删除和修改事件:
import static java.nio.file.StandardWatchEventKinds.*; … final Path path = Paths.get("C:/rafaelnadal"); WatchService watchService = FileSystems.getDefault().newWatchService(); … path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE); … watchService.close(); …
你将会收到注册目录的 WatchKey 对象,这是使用 WatchService 注册后被监控对象的唯一标识。你可以选择是否保留这个引用。在事件被触发后,WatchService 将会返回相关的 WatchKey。具体内容参看下文。
等待传入事件
等待传入事件需要一个无限循环。当事件被触发,监控服务将会把 WatchKey 放入监控队列中。无限循环可能是下面的类型:
while(true){ //接收并处理传入事件 … }
或者可能是下面的类型:
for(;;){ //接收并处理传入事件 … }
获取 WatchKey
从队列中获取 WatchKey 可以调用 WatchService 中的三个方法其中一个。三个方法功能都是获取队列中的下一个 Key 并且将它从队列中删除。不同的地方是如果没有可用的 Key 的处理方式。下面看看这三个方法:
- poll():如果没有可用的 key,将立即返回 null 值。
- poll(long, TimeUnit):如果没有可用的 key,则等待一个时间之后再试一次,如果依然没有可用的 key 则返回 null 值。等待时间是第一个参数,第二个参数是时间的单位(秒、分钟、小时或其它)。
- take():如果没有可用的 key,将一直等待,直到队列中有可用的 key或者无限循环结束。
下面的代码将演示如何在无限循环中调用这三个方法:
//没有参数的 poll 方法 while (true) { //retrieve and remove the next watch key final WatchKey key = watchService.poll(); //the thread flow gets here immediately with an available key or a null value … } //有参数的 poll 方法 while (true) { //retrieve and remove the next watch key final WatchKey key = watchService.poll(10, TimeUnit.SECONDS); //the thread flow gets here immediately if a key is available, or after 10 seconds //with an available key or null value … } //take 方法 while (true) { //retrieve and remove the next watch key final WatchKey key = watchService.take(); //the thread flow gets here immediately if a key is available, or it will wait until a //key is available, or the loop breaks … }
记住,每个 key 都有自己的状态,分别是就绪(ready),信号(signaled),无效(invalid):
- 就绪:当初次创建的时候,key 就处于就绪状态,意味着已经准备好接收事件。
- 信号:当 key 处于信号状态,表示至少有一个事件发生,并且 key 已在队列中等待。如果 key 处于信号状态,那么将会一直保持这个状态,直到调用 reset() 方法将 key 设置为就绪状态。如果 key 在信号状态的同时又发生了多个事件,那么这些事件将进入等待队列,key 本身所在的队列并不会重排。
- 无效:当 key 处于无效状态时,表示它不再是活跃状态。key 会一直保持有效状态,直到显式调用 cancel() 方法、或者目录变得不可访问、或者监控服务关闭,key 将会变为无效状态。可以调用 WatchKey.isValid() 方法来测试 key 是否处于有效状态。
注意,WatchKey 是线程安全的。
获取事件
当一个 key 处于信号状态,表示上面有一个或多个事件需要关注。可以调用 WatchKey.pollEvents() 方法获取并删除全部事件。这个方法不需要参数,调用后返回包含事件的 List 对象,List 中的类型是 WatchEvent<T>,它表示注册到 WatchService 中的对象上的事件。
如果没有获取到事件,pollEvents() 并不会等待,而是直接返回一个空的 List。
下面的代码将会从 key 获取事件,并遍历所有事件:
… while (true) { //retrieve and remove the next watch key final WatchKey key = watchService.take(); //get list of pending events for the watch key for (WatchEvent<?> watchEvent : key.pollEvents()) { … } … } …
WatchEvent 是不可变对象并且是线程安全的。
获取事件属性
WatchEvent<T> 中保存了事件的属性,可以调用 WatchEvent.kind() 方法获取事件类型,这个方法将返回 Kind<T> 类型的对象。
下面的代码演示了如何获取事件属性:
… //get list of pending events for the watch key for (WatchEvent<?> watchEvent : key.pollEvents()) { //get the kind of event (create, modify, delete) final Kind<?> kind = watchEvent.kind(); //handle OVERFLOW event if (kind == StandardWatchEventKinds.OVERFLOW) { continue; } System.out.println(kind); } …
除了事件类型,还可以调用 WatchEvent.count() 方法获取事件被观察次数(重复事件)。返回值是 int:
System.out.println(watchEvent.count());
获取事件的文件名
当文件的删除、创建或修改事件被触发后,我们可以通过事件的上下文获取文件名称(文件名存储在事件上下文中)。可以调用 WatchEvent.context() 方法来实现这个功能:
… final WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent; final Path filename = watchEventPath.context(); System.out.println(filename); …
将 Key 重置为就绪状态
如果 key 处于信号状态,那么将一直保持,直到调用 reset() 将其重置为就绪状态。如果 reset() 方法返回 true,表示 key 有效并且已经被重置,返回 false 表示重置失败,原因有可能是 key 不再有效。有的时候,如果 key 不再有效的话,我们需要跳出循环,例如,只有一个 key 的时候,没有必要再继续留在无限循环中,如下代码所示:
… while(true){ … //reset the key boolean valid = key.reset(); //exit loop if the key is not valid (if the directory was deleted, for example) if (!valid) { break; } } …
注意,如果忘记调用 reset() 或者调用 reset() 失败,那么 Key 将不再接收任何事件!
关闭 WatchService
当线程结束或监控服务关闭的时候,需要显式的调用 WatchService.close() 方法,或者将 WatchService 放入 try 语句块中:
try (WatchService watchService = FileSystems.getDefault().newWatchService()) { … }
当 WatchService 关闭后,当前的操作将会取消并且失效。如果服务关闭,任何操作都会抛出 ClosedWatchServiceException 异常。如果服务已经关闭,再调用这个方法不会有任何效果。
综合运用
下面的代码将会监控 C:\rafaelnadal 目录的创建、删除和修改事件。并且打印出事件类型和文件名。当程序运行后,可以手动创建、删除和修改此目录下的文件或目录,看看程序运行的效果。注意,此程序只对 C:\rafaelnadal 目录实现监控,其下的子目录并没有被监控。
import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardWatchEventKinds; import java.nio.file.WatchEvent; import java.nio.file.WatchEvent.Kind; import java.nio.file.WatchKey; import java.nio.file.WatchService; class WatchRafaelNadal { public void watchRNDir(Path path) throws IOException, InterruptedException { try (WatchService watchService = FileSystems.getDefault().newWatchService()) { path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE); //start an infinite loop while (true) { //retrieve and remove the next watch key final WatchKey key = watchService.take(); //get list of pending events for the watch key for (WatchEvent<?> watchEvent : key.pollEvents()) { //get the kind of event (create, modify, delete) final Kind<?> kind = watchEvent.kind(); //handle OVERFLOW event if (kind == StandardWatchEventKinds.OVERFLOW) { continue; } //get the filename for the event final WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent; final Path filename = watchEventPath.context(); //print it out System.out.println(kind + " -> " + filename); } //reset the key boolean valid = key.reset(); //exit loop if the key is not valid (if the directory was deleted, for example) if (!valid) { break; } } } } } public class Main { public static void main(String[] args) { final Path path = Paths.get("C:/rafaelnadal"); WatchRafaelNadal watch = new WatchRafaelNadal(); try { watch.watchRNDir(path); } catch (IOException | InterruptedException ex) { System.err.println(ex); } } }
注意,这段代码使用了无限循环,因此需要手动结束,或者自行编写一个结束机制。
文章来源:http://www.aptusource.org/2014/04/nio-2-implementing-a-watch-service/
发表评论
-
[NIO.2] 第四十一篇 随机访问文件概述
2014-04-29 14:51 1825我们已经看过很多顺序读取文件的例子,文件除了可以被顺序读取,还 ... -
[NIO.2] 第四十篇 监控目录树
2014-04-29 14:49 2102现在,我们编写一个应用来监控 C:\rafaelnadal 目 ... -
[NIO.2] 第三十八篇 监控服务 API
2014-04-21 14:13 2051Java 7 NIO.2 引入了线程安全的监控服务,用于监控对 ... -
[NIO.2] 第三十七篇 编写一个文件移动应用
2014-04-18 14:20 1376移动文件分为两个步骤,先拷贝文件,再删除源文件。 下面的代码 ... -
[NIO.2] 第三十六篇 编写一个文件拷贝应用
2014-04-18 14:18 1491拷贝目录树的时候,需要为文件和目录递归调用 Files.cop ... -
[NIO.2] 第三十五篇 编写一个文件删除应用
2014-04-17 18:22 1893如果要删除单个文件,可以直接调用 delete() 或 del ... -
[NIO.2] 第三十四篇 编写一个文件搜索应用
2014-04-14 15:39 1511大多数操作系统都提供了独立的工具用于文件搜索(例如,Linux ... -
[NIO.2] 第三十三篇 遍历目录树
2014-04-14 15:35 2453一旦你创建了遍历机制(实现 FileVisitor 接口或继承 ... -
[NIO.2] 第三十二篇 SimpleFileVisitor 类
2014-04-12 15:57 2074要实现 FileVisitor 接口就要实现接口上的所有方法, ... -
[NIO.2] 第三十一篇 FileVisitor 接口
2014-04-12 15:53 3262FileVisitor 接口提供了递归遍历文件树的支持。这个接 ... -
[NIO.2] 第三十篇 递归操作简述
2014-04-12 15:46 1094你可能知道,在编程中使用递归技术一直有争议,但是它的确简化了一 ... -
[NIO.2] 第二十九篇 删除、复制、移动目录和文件
2014-04-10 16:28 5400删除、拷贝和移动操作是最常见的文件操作。NIO.2 提供了独立 ... -
[NIO.2] 第二十八篇 创建临时目录和文件
2014-04-09 13:59 4575临时目录是用于存储临时文件的目录。临时目录的位置依赖操作系统。 ... -
[NIO.2] 第二十七篇 新建、读取和写出文件
2014-04-07 20:09 4235对文件来说,可能最常用的操作就是创建、读取和写出。NIO.2 ... -
[NIO.2] 第二十六篇 创建目录以及列出目录内容
2014-04-07 12:14 2541列出文件系统根目录 在 Java 6 中,获取根目录是通过 ... -
[NIO.2] 第二十五篇 文件及目录的校验
2014-04-05 16:26 1921在对文件或目录进行操 ... -
[NIO.2] 第二十四篇 定位链接所指向的目标文件位置
2014-04-03 18:30 1075调用 Files.readSymbolicLink() 方法可 ... -
[NIO.2] 第二十三篇 检验软链接
2014-04-03 12:12 1785Path 对象可能表示文件或链接。如果 Path 对象指向软链 ... -
[NIO.2] 第二十二篇 创建硬链接
2014-04-03 00:11 1927可以调用 createLink() 方法创建硬链接,它将会创建 ... -
[NIO.2] 第二十一篇 创建软链接
2014-04-02 18:35 3282在 NIO.2 中,创建软链接非常简单,只需要调用 Files ...
相关推荐
可以通过配置文件或API来实现服务降级和失败重试,例如设置`retries`参数来控制重试次数。 10. **Dubbo使用过程中都遇到了些什么问题?** 在使用Dubbo的过程中可能会遇到各种问题,如服务注册失败、网络连接不...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
2. 实现类:ArrayList、LinkedList、HashSet、HashMap等,分析其内部实现和性能特点。 3. 高级话题:并发集合类(ConcurrentHashMap, CopyOnWriteArrayList等)和泛型。 四、多线程与并发 1. 线程创建:Thread类、...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
- **社区支持**:两者都拥有活跃的社区支持,但Tomcat由于更广泛的使用范围,可能拥有更多的第三方插件和文档资源。 **1.5 本章小结** Jetty是一款优秀的Web服务器和Servlet容器,以其轻量级、高性能和高度可定制...
【标题】"Tomcat7.0.39官方安装包" 涉及的主要知识点是Apache Tomcat服务器的第七个主要版本的39次小更新。Tomcat是一款开源的Java Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,是Web应用程序...
- 一种开放标准,用于授权第三方应用访问用户资源。 47. **Docker在Java应用部署中的作用** - 提供了一种容器化的解决方案,便于应用的部署和管理。 48. **在Java中实现高效的日志记录** - 使用Log4j、SLF4J等...
#### 十三、Hadoop中的tar命令的实现 Hadoop支持通过tar命令打包文件,这在数据备份和迁移中非常有用。 **实现细节**: - **Hadoop Tar**:使用`hadoop archive`命令创建.tar.gz文件。 - **文件系统操作**:通过...
《深入剖析TOMCAT+Tomcat权威指南(第二版)》是两本关于Apache Tomcat服务器的重量级著作,它们详尽地阐述了Tomcat的内部工作机制、配置、优化以及故障排查等方面的知识,旨在帮助读者从新手到专家,全面掌握这款广泛...