Java 文件监视器

17 Mar 2025 | 6 分钟阅读

这是 Java 7 中引入的更近期的 IO API 的不太为人所知的特性之一,即 FileVisitor 接口。

WatchService 提供了一种独立于平台的、使用底层文件系统的原生机制来监视文件和目录更改的方法。通过此功能,Java 程序能够接收有关文件系统更改的即时通知。

要在应用程序中使用 WatchService 接口,您需要导入必要的类。

使用 WatchService

IDE 是该服务功能的流行示例。

您可能见过 IDE 能够实时识别其他地方源文件发生的更改。虽然有些 IDE 会在后台更新您的文件,但其他 IDE 则允许您通过对话框从文件系统中重新加载文件。

根据这一点,像 Play 这样的较新框架会在您在任何编辑器中进行更改时自动重新加载应用程序代码。

所有文件系统都包含一个名为文件更改通知的功能,这些应用程序会使用该功能。

我们可以编写代码来频繁检查文件系统,以了解对特定文件和目录的修改。然而,这种方法可能不够可扩展,特别是当有成百上千个文件和文件夹时。

Java 7 NIO 通过其 WatchService API 提供了一种可扩展的检查文件夹更改的方法。我们不需要开发自己的解决方案,因为它具有清晰的 API 且经过性能调优。

Watch 服务如何工作

使用 `java.nio.file.FileSystems` 创建 `WatchService` 实例是访问 `WatchService` 功能的第一步。FileSystems 类

然后必须创建我们要监视的目录的路径。

然后我们需要将路径注册到监视服务。此时,您需要理解两个关键概念:`WatchKey` 和 `StandardWatchEventKinds` 类。为了理解每个注册代码的位置,请查看以下内容。接下来我们将提供以下解释。

此处只需注意两个关键点:`WatchService` 实例作为第一个参数传递给 `path.register` API 调用,然后是 `StandardWatchEventKinds` 的可变参数。接下来,`WatchKey` 实例是注册过程的结果类型。

StandardWatchEventKinds

`StandardWatchEventKinds` 是 Java NIO.2 包中的一个枚举,它定义了 `WatchService` 可以监视的事件类型。它包含以下事件类型:

  1. ENTRY_CREATE: 在监视的目录中,当创建新文件或目录时,会触发此事件。
  2. ENTRY_MODIFY: 当监视的目录中的文件或目录被修改时,会触发此事件。这包括文件元数据的修改(例如最后修改时间)以及文件内容的更改。
  3. ENTRY_DELETE: 在监视的目录中删除文件或目录时,可以触发此事件。
  4. OVERFLOW: 在 `WatchService` 发生溢出的情况下,可以触发此事件,表明某些事件可能已丢失或被丢弃。在高流量的某些情况下,即使不常发生,也可能出现此事件。

WatchKey

此类表示将此类目录注册到监视服务。每当我们创建一个目录并询问我们注册的任何事件是否已发生时,监视服务就会将其实例返回给我们。

事件发生时,Watch 服务提供的回调方法不会被调用。我们只能通过轮询它来获取此数据。

我们可以使用 `poll` API 来执行以下操作:

每个 API 请求都会立即返回。如果队列中的任何监视事件已经发生,它会返回下一个队列中的监视键;否则,它会返回 null。

另一个需要延迟的情况是,它被重载了。

此 API 调用的返回值与前一个类似。它不会立即返回 null,而是会阻塞 `timeout units` 来提供更多时间让事件发生。

最后,我们可以使用 `take` API。

在事件发生之前,此最后一个方法将被阻塞。

我们在此处必须注意一个重要事项:一旦 `WatchKey` 对象由任何 `poll` 或 `take` API 返回,如果未调用 `reset` API,它将停止捕获事件。

每次 `poll` 操作返回时,`watch key` 实例都已从 `watch service` 队列中移除。在调用 `reset` API 后,它将被返回到队列中以监视更多事件。

监视服务将需要在循环中使用,我们在其中不断检查监视目录中的更改并采取相应行动。为此,我们可以使用如下的惯用法:

我们创建一个 `watch key` 来存储 `poll` 操作的结果。`while` 循环将保持不活动状态,除非条件表达式返回 `watch key` 或 null。

当我们获得 `watch key` 后,`while` 循环将执行其内部方法。使用 `WatchKey.pollEvents` API 返回最近事件的列表。接下来,我们使用 `for each` 循环逐个处理每个事件。

在所有事件都处理完毕后,我们必须使用 `reset` API 来重新排队 `watch key`。

实施

在上一部分中,我们已经讨论了 `WatchService` API 的内部工作原理和实际应用,这使我们可以继续进行全面而实际的示例。

出于可移植性方面的考虑,我们将监视用户主目录中的活动,该目录应在所有当前操作系统上都可以访问。

文件名: FileWatchService.java

请按照以下步骤运行程序。

步骤 1: 首先,我们创建了 `filewatcerdemo` 文件夹。

Java File Watcher

步骤 2: 在 `filewatcherdemo` 文件夹内,进入 `src`,创建一个名为 "com.watcher.demo" 的包,并在该包中创建一个名为 `FileWatcherService.java` 的类。

步骤 3: 现在,在 `FileWatchService.java` 文件中键入程序。现在创建一个您选择的新文件夹,我们已经创建了 "watcher",并将其保存在系统中。现在复制系统的路径并粘贴到上面的代码中。

Java File Watcher

步骤 4: 现在复制 `watcher` 文件的路径并粘贴到上面的代码中。

Java File Watcher

步骤 4: 现在保存代码,先编译,然后运行程序。现在打开我们创建的 `watcher` 文件夹,创建一个新的 `.txt` 格式的下一个文本文件。

我们可以观察到代码执行了以下命令:事件类型 ENTRY_CREATE,受影响文件:New Text Document.txt

Java File Watcher

步骤 5: 如果我们尝试删除文本文件,我们可以观察到代码执行了以下命令:事件类型 ENTRY_DELETE,受影响文件:New Text Document.txt

Java File Watcher

步骤 6: 如果我们尝试修改文本文件,我们可以观察到代码执行了以下命令:事件类型 ENTRY_MODIFY,受影响文件:New Text Document.txt

Java File Watcher

您可以在用户主目录中创建文件或目录,修改文件内容,甚至删除文件。所有这些操作都将在控制台中记录下来。