WatchService能够帮助咱们监控一些文件是否作了更改,若是文件作了更改,能够帮助咱们去作一些响应,好比,配置文件修改了,那么系统应该从新加载一下配置文件,这样能够将最新的配置加载进来。html
The watch service exits when either the thread exits or when it is closed (by invoking its closed method。当前启动的线程退出或者调用closed方法关闭的时候,watch service也会推出。java
此类表明着一个Object(文件或者文件夹) 注册到WatchService后,返回一个WatchKey类。反应当前所注册的Object状态的类。此类封装了不一样事件的状态值,好比,当文件(文件夹)被修改或者被删除或者建立的时候,此类首先产生一个信号量,等待消费者来取而且该WatchKey将会进入到WatchService的队列中。若是WatchKey已经进入到队列当中,可是又有了变化,将不会再次进入到队列当中。oracle
WatchService.take()方法能够取到队列的WatchKey.app
此类表明文件系统上面的一个文件jsp
此类表明文件的一个具体事件。ide
WatchEvent测试
To implement this functionality, called file change notification, a program must be able to detect what is happening to the relevant directory on the file system. One way to do so is to poll the file system looking for changes, but this approach is inefficient. It does not scale to applications that have hundreds of open files or directories to monitor.ui
要作到文件变动提醒功能,有一种办法就是轮询文件系统上面的文件确认是否有变动,可是显然这种作法效率不高。this
The java.nio.file
package provides a file change notification API, called the Watch Service API. This API enables you to register a directory (or directories) with the watch service. When registering, you tell the service which types of events you are interested in: file creation, file deletion, or file modification. When the service detects an event of interest, it is forwarded to the registered process. The registered process has a thread (or a pool of threads) dedicated to watching for any events it has registered for. When an event comes in, it is handled as needed.spa
Java WatchService 服务提供API,能够注册你感兴趣的事件,当service 发现注册的事件后,就交给处理线程作处理。
当收到一个文件变动事件的时候,并不表示该文件已经变动完毕,有可能还在变动当中。
The Watch Service API is designed for applications that need to be notified about file change events. It is well suited for any application, like an editor or IDE, that potentially has many open files and needs to ensure that the files are synchronized with the file system. It is also well suited for an application server that watches a directory, perhaps waiting for .jsp
or .jar
files to drop, in order to deploy them.
This API is not designed for indexing a hard drive. Most file system implementations have native support for file change notification. The Watch Service API takes advantage of this support where available. However, when a file system does not support this mechanism, the Watch Service will poll the file system, waiting for events.
Oracle 官方给出的例子代码:
package com.hpe.common.audit; /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Oracle nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import java.nio.file.*; import static java.nio.file.StandardWatchEventKinds.*; import static java.nio.file.LinkOption.*; import java.nio.file.attribute.*; import java.io.*; import java.util.*; /** * Example to watch a directory (or tree) for changes to files. */ public class WatchDir { private final WatchService watcher; private final Map<WatchKey,Path> keys; private final boolean recursive; private boolean trace = false; @SuppressWarnings("unchecked") static <T> WatchEvent<T> cast(WatchEvent<?> event) { return (WatchEvent<T>)event; } /** * Register the given directory with the WatchService */ private void register(Path dir) throws IOException { WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); if (trace) { Path prev = keys.get(key); if (prev == null) { System.out.format("register: %s\n", dir); } else { if (!dir.equals(prev)) { System.out.format("update: %s -> %s\n", prev, dir); } } } keys.put(key, dir); } /** * Register the given directory, and all its sub-directories, with the * WatchService. */ private void registerAll(final Path start) throws IOException { // register directory and sub-directories Files.walkFileTree(start, new SimpleFileVisitor<Path>() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { register(dir); return FileVisitResult.CONTINUE; } }); } /** * Creates a WatchService and registers the given directory */ WatchDir(Path dir, boolean recursive) throws IOException { this.watcher = FileSystems.getDefault().newWatchService(); this.keys = new HashMap<WatchKey,Path>(); this.recursive = recursive; if (recursive) { System.out.format("Scanning %s ...\n", dir); registerAll(dir); System.out.println("Done."); } else { register(dir); } // enable trace after initial registration this.trace = true; } /** * Process all events for keys queued to the watcher */ void processEvents() { for (;;) {//这是个死循环 // wait for key to be signalled WatchKey key; try { key = watcher.take(); } catch (InterruptedException x) { return; } Path dir = keys.get(key); if (dir == null) { System.err.println("WatchKey not recognized!!"); continue; } for (WatchEvent<?> event: key.pollEvents()) { WatchEvent.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(); Path child = dir.resolve(name); // print out event System.out.format("%s: %s\n", event.kind().name(), child); // if directory is created, and watching recursively, then // register it and its sub-directories if (recursive && (kind == ENTRY_CREATE)) { try { if (Files.isDirectory(child, NOFOLLOW_LINKS)) { registerAll(child); } } catch (IOException x) { // ignore to keep sample readbale } } } // reset key and remove from set if directory no longer accessible boolean valid = key.reset(); if (!valid) { keys.remove(key); // all directories are inaccessible if (keys.isEmpty()) { break; } } } } static void usage() { System.err.println("usage: java WatchDir [-r] dir"); System.exit(-1); } /****************************************** * 使用方法,能够传入两个参数, * 第一个参数表示是否循环遍历该文件夹(能够不传), * 第二个参数表明要监控的文件路径。 * * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // parse arguments if (args.length == 0 || args.length > 2){ usage(); } boolean recursive = false; int dirArg = 0; if (args[0].equals("-r")) { if (args.length < 2){ usage(); } recursive = true; dirArg++; } // register directory and process its events Path dir = Paths.get(args[dirArg]); new WatchDir(dir, recursive).processEvents(); } }
输出结果:
Scanning E:\work\ftp_file\download ...
Done.
ENTRY_CREATE: E:\work\ftp_file\download\New Text Document.txt
ENTRY_DELETE: E:\work\ftp_file\download\New Text Document.txt
ENTRY_CREATE: E:\work\ftp_file\download\11.txt
ENTRY_MODIFY: E:\work\ftp_file\download\11.txt
ENTRY_MODIFY: E:\work\ftp_file\download\11.txt
http://codingjunkie.net/java-7-watchservice/