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.但是,当文件系统不支持此机制时,监视服务将轮询文件系统,等待事件发生。