WatchService 是 Java NIO 包 (java.nio.file) 中提供的一个用于监控文件系统变化的 API。它允许应用程序监听目录中的文件创建、修改和删除事件。

基本原理

WatchService 使用操作系统提供的文件系统通知机制:

  • Windows: 使用 ReadDirectoryChangesW

  • Linux: 使用 inotify

  • Mac OS X: 使用 FSEvents

 

WatchService 和定时任务轮询是两种不同的文件监控策略,它们在资源消耗方面有显著差异。

资源消耗对比

特性 WatchService 定时任务轮询
工作机制 基于操作系统事件通知 定期主动扫描文件系统
CPU使用 低(事件驱动,空闲时几乎不消耗CPU) 高(每次扫描都需要CPU计算)
内存使用 中等(维护事件队列和状态) 取决于扫描范围和频率
I/O操作 极少(仅在有变化时触发) 高(每次扫描都需要读取文件系统)
响应延迟 近实时(毫秒级) 取决于轮询间隔(秒级或更长)
可扩展性 好(可监控大量文件) 差(大量文件时性能下降明显)

直接上实现代码:

import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.*; /*
监控指定目录下文件的创建、删除和修改
*/
public class DirectoryWatcher {
public static void main(String[] args) throws Exception {
// 1. 创建WatchService实例
WatchService watcher = FileSystems.getDefault().newWatchService(); // 2. 注册要监控的目录
Path dir = Paths.get("D:/2"); // 替换为你要监控的目录
WatchKey key = dir.register(watcher,
ENTRY_CREATE,
ENTRY_DELETE,
ENTRY_MODIFY); System.out.println("开始监控: " + dir); // 3. 事件处理循环
while (true) {
// 等待并获取下一个WatchKey
key = watcher.take(); // 处理所有事件
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind(); // 处理OVERFLOW事件(可能丢失或丢弃的事件)
if (kind == OVERFLOW) {
continue;
} // 获取事件上下文(通常是文件名)
WatchEvent<Path> ev = (WatchEvent<Path>) event;
Path filename = ev.context(); System.out.printf("事件类型: %s, 文件: %s%n", kind.name(), filename); // 这里可以添加自定义的业务处理逻辑
if (kind == ENTRY_CREATE) {
System.out.println("新文件创建: " + filename);
} else if (kind == ENTRY_DELETE) {
System.out.println("文件删除: " + filename);
} else if (kind == ENTRY_MODIFY) {
System.out.println("文件修改: " + filename);
}
} // 4. 重置WatchKey以继续接收事件
boolean valid = key.reset();
if (!valid) {
System.out.println("WatchKey不再有效");
break;
}
}
}
}

运行效果:

开始监控: D:\2
事件类型: ENTRY_DELETE, 文件: _2025-03-17_13-26-32
文件删除: _2025-03-17_13-26-32
事件类型: ENTRY_CREATE, 文件: 新建文本文档.txt
新文件创建: 新建文本文档.txt
事件类型: ENTRY_DELETE, 文件: 新建文本文档.txt
文件删除: 新建文本文档.txt
事件类型: ENTRY_CREATE, 文件: 1.txt
新文件创建: 1.txt

import java.nio.file.*;

import static java.nio.file.StandardWatchEventKinds.*;

/*
监控指定目录下文件的创建、删除和修改
*/
import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.*;
import java.io.IOException; /*
监控指定目录(包含子文件夹)下文件的创建、删除和修改
*/
public class RecursiveDirectoryWatcher {
private final WatchService watcher;
private final Path rootDir; public RecursiveDirectoryWatcher(Path dir) throws IOException {
this.watcher = FileSystems.getDefault().newWatchService();
this.rootDir = dir; // 递归注册所有子目录
registerAllSubdirectories(dir);
} private void registerAllSubdirectories(final Path start) throws IOException {
Files.walk(start)
.filter(Files::isDirectory)
.forEach(subDir -> {
try {
System.out.println("注册监控目录: " + subDir);
subDir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
} catch (IOException e) {
System.err.println("无法注册目录 " + subDir + ": " + e);
}
});
} public void startWatching() {
System.out.println("开始监控目录树: " + rootDir); while (true) {
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException e) {
System.err.println("监控被中断");
return;
} for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind(); if (kind == OVERFLOW) {
continue;
} @SuppressWarnings("unchecked")
WatchEvent<Path> ev = (WatchEvent<Path>) event;
Path filename = ev.context();
Path dir = (Path) key.watchable();
Path fullPath = dir.resolve(filename); System.out.printf("事件类型: %s, 文件: %s%n", kind.name(), fullPath); // 如果是新建目录,则注册监控
if (kind == ENTRY_CREATE && Files.isDirectory(fullPath)) {
try {
registerAllSubdirectories(fullPath);
} catch (IOException e) {
System.err.println("无法注册新目录 " + fullPath + ": " + e);
}
}
} if (!key.reset()) {
System.out.println("WatchKey不再有效");
break;
}
}
} public static void main(String[] args) throws IOException {
Path dir = Paths.get("D:/2"); // 替换为你要监控的目录
new RecursiveDirectoryWatcher(dir).startWatching();
}
}
import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.*;
import java.io.IOException; /*
监控指定目录(指定类型文件)文件的创建、删除和修改
*/
public class TxtFileWatcher {
private final WatchService watcher;
private final Path dir; public TxtFileWatcher(Path dir) throws IOException {
this.watcher = FileSystems.getDefault().newWatchService();
this.dir = dir; // 注册监控目录
dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
} public void startWatching() {
System.out.println("开始监控.txt文件变化,目录: " + dir); while (true) {
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException e) {
System.err.println("监控被中断");
return;
} for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind(); if (kind == OVERFLOW) {
continue;
} @SuppressWarnings("unchecked")
WatchEvent<Path> ev = (WatchEvent<Path>) event;
Path filename = ev.context(); // 只处理.txt文件
if (filename.toString().endsWith(".txt")) {
Path fullPath = dir.resolve(filename); System.out.printf("事件类型: %s, 文件: %s%n", kind.name(), fullPath); // 这里可以添加对.txt文件的特定处理逻辑
if (kind == ENTRY_CREATE) {
System.out.println("新的.txt文件创建: " + fullPath);
} else if (kind == ENTRY_MODIFY) {
System.out.println("txt文件被修改: " + fullPath);
// 可以在这里读取文件内容等操作
} else if (kind == ENTRY_DELETE) {
System.out.println("txt文件被删除: " + fullPath);
}
}
} if (!key.reset()) {
System.out.println("WatchKey不再有效");
break;
}
}
} public static void main(String[] args) throws IOException {
Path dir = Paths.get("D:/2"); // 替换为你要监控的目录
new TxtFileWatcher(dir).startWatching();
}
}

Java WatchService监控指定路径下的文件新增、删除和修改(子文件夹、指定文件类型)的更多相关文章

  1. java监控指定路径下文件及文件夹变化

    之前用jdk7的WatchService API(java.nio.file包)来做目录下的子文件监控,后改为使用commons-io包.主要有下面几点不同:1. WatchService是采用扫描式 ...

  2. java 压缩文件 传入文件数组,压缩文件,在指定路径下生成指定文件名的压缩文件

    /** * 传入文件数组,压缩文件,在指定路径下生成指定文件名的压缩文件 * * @param files * 文件数组 * @param strZipName * 压缩文件路径及文件名 * @thr ...

  3. C#实现把指定文件夹下的所有文件复制到指定路径下以及修改指定文件的后缀名

    1.实现把指定文件夹下的所有文件复制到指定路径下 public static void copyFiles(string path) { DirectoryInfo dir = new Directo ...

  4. python之实现循环查看指定路径下的所有文件---os.walk

    循环查看指定路径下的所有文件.文件夹,包含隐藏文件注:“.filename” 以点开头的是隐藏文件 import os for cur_path,cur_dirs,cur_files in os.wa ...

  5. Python3在指定路径下递归定位文件中出现的字符串

    [本文出自天外归云的博客园] 脚本功能:在指定的路径下递归搜索,找出指定字符串在文件中出现的位置(行信息). 用到的python特性: 1. PEP 318 -- Decorators for Fun ...

  6. 【Lua】关于遍历指定路径下所有目录及文件

    关于Lua中如何遍历指定文件路径下的所有文件,需要用到Lua的lfs库. 首先创建一个temp.lua文件,用编辑器打开: 要使用lfs库,首先需要把lfs库加载进来 require("lf ...

  7. Python获取指定路径下所有文件的绝对路径

    需求 给出制定目录(路径),获取该目录下所有文件的绝对路径: 实现 方式一: import os def get_file_path_by_name(file_dir): ''' 获取指定路径下所有文 ...

  8. Python小代码_15_遍历指定路径下的所有文件和文件夹,并格式化输出文件路径文件名和文件夹名,文件大小,修改时间

    遍历指定路径下的所有文件和文件夹,并格式化输出文件路径文件名和文件夹名,文件大小,修改时间 import osimport datetime def print_tree(dir_path): for ...

  9. Windows 定时删除指定路径下N天前的日志文件

    Windows 定时删除指定路径下N天前的日志文件 Windows 下bat脚本文件的内容为 1. 删除指定路径下5天前的所有文件 @echo off set SrcDir=E:\WORK\Git s ...

  10. 将指定路径下的所有SVG文件导出成PNG等格式的图片(缩略图或原图大小)

    原文:将指定路径下的所有SVG文件导出成PNG等格式的图片(缩略图或原图大小) WPF的XAML文档(Main.xaml): <Window x:Class="SVG2Image.Ma ...

随机推荐

  1. Solution Set -「NOIP Simu.」20221008

    \(\mathscr{A}\sim\)「CF 1680E」Moving Chips   Link & Submission.   Tag:「水题无 tag」   温暖签到惹, DP 一下就好了 ...

  2. [Java] 计算Java对象大小

    序 在Java应用程序的性能优化场景中,时常需要考虑Java对象的大小,以便评估后,进一步提出优化方案: 占用内存的大小.(比如 本地内存) 对象数据在网络传输中占用的网络带宽 对象数据在存储时占用的 ...

  3. CDS标准视图:维修工单工艺数据 I_MAINTORDEROPERATIONDATA

    视图名称:维修工单工艺数据 I_MAINTORDEROPERATIONDATA 视图类型:基础 视图代码: 点击查看代码 @EndUserText.label: 'Maintenance Order ...

  4. 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(一):从.NET IoT入门开始

    前言 为什么我会想着制作一个智能桌面机器人呢?自问自答一下,看过我之前文章的小伙伴应该都知道我之前有为稚晖君开源的ElectronBot桌面机器人开发过一个桌面上位机软件叫电子脑壳,由于Electro ...

  5. WPF create Flower shape

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  6. UWP 系统通知测试

    code: using System; using System.Collections.Generic; using System.IO; using System.Linq; using Syst ...

  7. RFID基础——概念与分类

    RFID 的全称是射频识别技术(Radio Frequency Identification).是一项利用射频信号通过空间耦合(交变磁场或电磁场)实现无接触信息传递并通过所传递的信息达到识别目的的技术 ...

  8. RestClient 通过拦截器实现请求加密

    今天我发现了一个关于请求加密的有效写法,特此分享给大家.如果你的加密需求是将请求参数也包含在内,通常情况下,我们需要先将请求体转换成 JSON 格式或其他对象类型,再使用字符串的形式进行加密操作.以下 ...

  9. Java代码覆盖率工具之Jacoco

    Java代码覆盖率工具之Jacoco JaCoCo(Java Code Coverage)是一款面向Java语言的开源代码覆盖率工具,以其小型化和轻量化著称.它能够提供代码在测试过程中的覆盖率信息,帮 ...

  10. 历时两天半由浅入深总结了20道Vue高频面试题

    作为一个程序员如果你想要找到你心仪的工作,不可避免的就会问到很多八股文,虽然有的和工作没有半毛钱关系,但是你如果想要通过面试还必须得会.所以我最近开始总结一些面试题,一是为了加强自己的理解能够找到一份 ...