The Java Tutorials have been written for JDK 8.Java教程是为JDK 8编写的。Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.本页中描述的示例和实践没有利用后续版本中引入的改进,并且可能使用不再可用的技术。See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.有关所有JDK版本的新功能、增强功能以及已删除或不推荐的选项的信息,请参阅JDK发行说明。
Have you ever found yourself editing a file, using an IDE or another editor, and a dialog box appears to inform you that one of the open files has changed on the file system and needs to be reloaded? 您是否曾经发现自己在使用IDE或其他编辑器编辑文件时,会出现一个对话框,通知您文件系统中打开的一个文件已更改,需要重新加载?Or perhaps, like the NetBeans IDE, the application just quietly updates the file without notifying you. 或者,像NetBeans IDE一样,应用程序只是悄悄地更新文件而不通知您。The following sample dialog box shows how this notification looks with the free editor, jEdit:以下示例对话框显示了此通知在自由编辑器jEdit中的外观:

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.它不能扩展到有数百个打开的文件或目录要监视的应用程序。
The java.nio.file package provides a file change notification API, called the Watch Service API. java.nio.file包提供了一个文件更改通知API,称为监视服务API。This API enables you to register a directory (or directories) with the watch service. 此API允许您向监视服务注册一个或多个目录。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.当事件发生时,会根据需要进行处理。
This section covers the following:本节包括以下内容:
The WatchService API is fairly low level, allowing you to customize it. WatchService API的级别相当低,允许您对其进行自定义。You can use it as is, or you can choose to create a high-level API on top of this mechanism so that it is suited to your particular needs.您可以按原样使用它,也可以选择在这个机制之上创建一个高级API,以便它适合您的特定需求。
Here are the basic steps required to implement a watch service:以下是实现监视服务所需的基本步骤:
WatchService "watcher" for the file system.WatchService“观察者”。watcher注册它。WatchKey instance for each directory that you register.WatchKey实例。closed method).closed方法)时,监视服务退出。WatchKeys are thread-safe and can be used with the java.nio.concurrent package. WatchKeys是线程安全的,可以与java.nio.concurrent包一起使用。You can dedicate a thread pool to this effort.您可以将一个线程池专门用于此工作。
Because this API is more advanced, try it out before proceeding. 由于此API更高级,请在继续之前试用它。Save the 将WatchDir example to your computer, and compile it. WatchDir示例保存到您的计算机中,并对其进行编译。Create a 创建将传递给示例的test directory that will be passed to the example. test目录。WatchDir uses a single thread to process all events, so it blocks keyboard input while waiting for events. WatchDir使用单个线程处理所有事件,因此它在等待事件时阻止键盘输入。Either run the program in a separate window, or in the background, as follows:在单独的窗口或后台运行程序,如下所示:
java WatchDir test &
Play with creating, deleting, and editing files in the 在test directory. test目录中创建、删除和编辑文件。When any of these events occurs, a message is printed to the console. 当这些事件中的任何一个发生时,将向控制台打印一条消息。When you have finished, delete the 完成后,删除test directory and WatchDir exits. test目录并退出WatchDir。Or, if you prefer, you can manually kill the process.或者,如果愿意,可以手动终止该进程。
You can also watch an entire file tree by specifying the 您还可以通过指定-r option. -r选项来查看整个文件树。When you specify 指定-r, WatchDir walks the file tree, registering each directory with the watch service.-r时,WatchDir遍历文件树,向监视服务注册每个目录。
The first step is to create a new 第一步是使用WatchService by using the newWatchService method in the FileSystem class, as follows:FileSystem类中的newWatchService方法创建一个新的WatchService,如下所示:
WatchService watcher = FileSystems.getDefault().newWatchService();
Next, register one or more objects with the watch service. 接下来,向监视服务注册一个或多个对象。Any object that implements the 任何实现Watchable interface can be registered. Watchable接口的对象都可以注册。The Path class implements the Watchable interface, so each directory to be monitored is registered as a Path object.Path类实现了Watchable接口,因此要监视的每个目录都注册为Path对象。
As with any 与任何可观察对象一样,Watchable, the Path class implements two register methods. Path类实现两个register方法。This page uses the two-argument version, 此页面使用两个参数版本register(WatchService, WatchEvent.Kind<?>...). register(WatchService, WatchEvent.Kind<?>...)。(The three-argument version takes a (三参数版本采用WatchEvent.Modifier, which is not currently implemented.)WatchEvent.Modifier,该修饰符当前未实现。)
When registering an object with the watch service, you specify the types of events that you want to monitor. 向watch服务注册对象时,指定要监视的事件类型。The supported 支持的StandardWatchEventKinds event types follow:StandardWatchEventKinds事件类型如下:
ENTRY_CREATE – ENTRY_DELETE – ENTRY_MODIFY – OVERFLOW – OVERFLOW event to receive it.OVERFLOW事件即可接收它。The following code snippet shows how to register a 以下代码段显示了如何为所有三种事件类型注册Path instance for all three event types:Path实例:
import static java.nio.file.StandardWatchEventKinds.*;
Path dir = ...;
try {
WatchKey key = dir.register(watcher,
ENTRY_CREATE,
ENTRY_DELETE,
ENTRY_MODIFY);
} catch (IOException x) {
System.err.println(x);
}The order of events in an event processing loop follow:事件处理循环中的事件顺序如下:
poll – null value, if unavailable.null值。poll(long, TimeUnit) – TimeUnit argument determines whether the specified time is nanoseconds, milliseconds, or some other unit of time.TimeUnit参数确定指定的时间是纳秒、毫秒还是其他时间单位。take – List of WatchEvents from the pollEvents method.pollEvents方法获取WatchEvents的List。kind method. kind方法检索事件的类型。OVERFLOW event. OVERFLOW事件。context method is used to retrieve it.context方法检索它。ready state by invoking reset. reset将密钥恢复到ready状态。false, the key is no longer valid and the loop can exit. false,则键不再有效,循环可以退出。reset, this key will not receive any further events.reset失败,此键将不会接收任何其他事件。A watch key has a state. 监视密钥有一个状态。At any given time, its state might be one of the following:在任何给定时间,其状态可能为以下状态之一:
Ready indicates that the key is ready to accept events. Ready表示密钥已准备好接受事件。Signaled indicates that one or more events are queued. Signaled表示一个或多个事件已排队。reset method is invoked.reset方法之前,钥匙不再处于就绪状态。Invalid indicates that the key is no longer active. Invalid表示密钥不再处于活动状态。Here is an example of an event processing loop. 下面是一个事件处理循环的示例。It is taken from the 它取自Email example, which watches a directory, waiting for new files to appear. Email示例,该示例监视一个目录,等待新文件出现。When a new file becomes available, it is examined to determine if it is a 当新文件可用时,将使用text/plain file by using the probeContentType(Path) method. probeContentType(Path)方法对其进行检查,以确定它是否为文本/普通文件。The intention is that 其目的是将text/plain files will be emailed to an alias, but that implementation detail is left to the reader.text/plain文件通过电子邮件发送给别名,但实现细节留给读者。
The methods specific to the watch service API are shown in bold:特定于监视服务API的方法以粗体显示:
for (;;) {
// wait for key to be signaled
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException x) {
return;
}
for (WatchEvent<?> event: key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
// This key is registered only
// for ENTRY_CREATE events,
// but an OVERFLOW event can
// occur regardless if events
// are lost or discarded.
if (kind == OVERFLOW) {
continue;
}
// The filename is the
// context of the event.
WatchEvent<Path> ev = (WatchEvent<Path>)event;
Path filename = ev.context();
// Verify that the new
// file is a text file.
try {
// Resolve the filename against the directory.
// If the filename is "test" and the directory is "foo",
// the resolved name is "test/foo".
Path child = dir.resolve(filename);
if (!Files.probeContentType(child).equals("text/plain")) {
System.err.format("New file '%s'" +
" is not a plain text file.%n", filename);
continue;
}
} catch (IOException x) {
System.err.println(x);
continue;
}
// Email the file to the
// specified email alias.
System.out.format("Emailing file %s%n", filename);
//Details left to reader....
}
// Reset the key -- this step is critical if you want to
// receive further watch events. If the key is no longer valid,
// the directory is inaccessible so exit the loop.
boolean valid = key.reset();
if (!valid) {
break;
}
}The file name is retrieved from the event context. 从事件上下文中检索文件名。The Email example retrieves the file name with this code:Email示例使用以下代码检索文件名:
WatchEvent<Path> ev = (WatchEvent<Path>)event; Path filename = ev.context();
When you compile the 编译Email example, it generates the following error:Email示例时,会生成以下错误:
Note: Email.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details.
This error is a result of the line of code that casts the 此错误是将WatchEvent<T> to a WatchEvent<Path>. WatchEvent<T>强制转换为WatchEvent<Path>结果。The WatchDir example avoids this error by creating a utility cast method that suppresses the unchecked warning, as follows:WatchDir示例通过创建抑制未检查警告的实用程序强制转换方法来避免此错误,如下所示:
@SuppressWarnings("unchecked")
static <T> WatchEvent<T> cast(WatchEvent<?> event) {
return (WatchEvent<Path>)event;
}If you are unfamiliar with the 如果您不熟悉@SuppressWarnings syntax, see Annotations.@SuppressWarnings语法,请参阅注释。
The Watch Service API is designed for applications that need to be notified about file change events. 监视服务API是为需要通知文件更改事件的应用程序而设计的。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. 它非常适合任何应用程序,如编辑器或IDE,这些应用程序可能有许多打开的文件,并且需要确保这些文件与文件系统同步。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..jsp或.jar文件删除,以便部署它们。
This API is not designed for indexing a hard drive. 此API不是为索引硬盘驱动器而设计的。Most file system implementations have native support for file change notification. 大多数文件系统实现都具有对文件更改通知的本机支持。The Watch Service API takes advantage of this support where available. 监视服务API在可用的情况下利用了这种支持。However, when a file system does not support this mechanism, the Watch Service will poll the file system, waiting for events.但是,当文件系统不支持此机制时,监视服务将轮询文件系统,等待事件发生。