Java WatchService监控指定路径下的文件新增、删除和修改(子文件夹、指定文件类型)
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监控指定路径下的文件新增、删除和修改(子文件夹、指定文件类型)的更多相关文章
- java监控指定路径下文件及文件夹变化
之前用jdk7的WatchService API(java.nio.file包)来做目录下的子文件监控,后改为使用commons-io包.主要有下面几点不同:1. WatchService是采用扫描式 ...
- java 压缩文件 传入文件数组,压缩文件,在指定路径下生成指定文件名的压缩文件
/** * 传入文件数组,压缩文件,在指定路径下生成指定文件名的压缩文件 * * @param files * 文件数组 * @param strZipName * 压缩文件路径及文件名 * @thr ...
- C#实现把指定文件夹下的所有文件复制到指定路径下以及修改指定文件的后缀名
1.实现把指定文件夹下的所有文件复制到指定路径下 public static void copyFiles(string path) { DirectoryInfo dir = new Directo ...
- python之实现循环查看指定路径下的所有文件---os.walk
循环查看指定路径下的所有文件.文件夹,包含隐藏文件注:“.filename” 以点开头的是隐藏文件 import os for cur_path,cur_dirs,cur_files in os.wa ...
- Python3在指定路径下递归定位文件中出现的字符串
[本文出自天外归云的博客园] 脚本功能:在指定的路径下递归搜索,找出指定字符串在文件中出现的位置(行信息). 用到的python特性: 1. PEP 318 -- Decorators for Fun ...
- 【Lua】关于遍历指定路径下所有目录及文件
关于Lua中如何遍历指定文件路径下的所有文件,需要用到Lua的lfs库. 首先创建一个temp.lua文件,用编辑器打开: 要使用lfs库,首先需要把lfs库加载进来 require("lf ...
- Python获取指定路径下所有文件的绝对路径
需求 给出制定目录(路径),获取该目录下所有文件的绝对路径: 实现 方式一: import os def get_file_path_by_name(file_dir): ''' 获取指定路径下所有文 ...
- Python小代码_15_遍历指定路径下的所有文件和文件夹,并格式化输出文件路径文件名和文件夹名,文件大小,修改时间
遍历指定路径下的所有文件和文件夹,并格式化输出文件路径文件名和文件夹名,文件大小,修改时间 import osimport datetime def print_tree(dir_path): for ...
- Windows 定时删除指定路径下N天前的日志文件
Windows 定时删除指定路径下N天前的日志文件 Windows 下bat脚本文件的内容为 1. 删除指定路径下5天前的所有文件 @echo off set SrcDir=E:\WORK\Git s ...
- 将指定路径下的所有SVG文件导出成PNG等格式的图片(缩略图或原图大小)
原文:将指定路径下的所有SVG文件导出成PNG等格式的图片(缩略图或原图大小) WPF的XAML文档(Main.xaml): <Window x:Class="SVG2Image.Ma ...
随机推荐
- 在 ASP.NET Core WebAPI如何实现版本控制?
在 ASP.NET Core WebAPI 中实现版本控制(Versioning)是一种常见的做法,用于管理 API 的演进和兼容性.通过版本控制,我们可以在不破坏现有客户端的情况下引入新功能或修改现 ...
- bitset 学习笔记
引入 顾名思义, \(\texttt{bitset}\) 是用 \(\texttt{bit}\) 组成的 \(\texttt{set}\); 区别于普通的 \(\texttt{bool []}\) 或 ...
- 2020年最新版区块链面试题1-copy
1. 什么是区块链? 回答:区块链是不间断的经济交易数字分类帐,可以进行编程,以记录不仅是金融交易,还可以记录几乎所有有价值的东西.简单来说,它是一个不可变记录的分散式分布式数据库,该数据库由计算机集 ...
- Idea创建maven项目流程、修改默认配置、及注意事项
这里所演示的环境: windows7+jdk1.7.0_80+tomcat8.5.41+maven3.0.5+idea2017.3.6 1.idea使用指定maven版本 打开idea,使用快捷键ct ...
- 【分享】 100+ 套开源大数据可视化大屏Html5模板,全网最炫!
今天给大家分享 100+ 套开源大数据可视化炫酷大屏Html5模板,全网最新.最多.最全.最酷.最炫的大数据可视化模板! 项目介绍 BigDataView提供了100+套大数据可视化炫酷大屏Html5 ...
- 天翼云VPC支持专线健康检查介绍
本文分享自天翼云开发者社区<天翼云VPC支持专线健康检查介绍>,作者:汪****波 天翼云支持本地数据中心IDC(Internet Data Center)通过冗余专线连接到天翼云云上专有 ...
- 任务调度器Azkaban(Azkaban环境部署)
文章链接:https://www.cnblogs.com/liugp/p/16273966.html
- 定制化训练DeepSeek模型:LoAR、COT推理与SFT技术应用
DeepSeek-R1 模型微调系列 DeepSeek-R1 模型微调系列一. 前言介绍本文内容:1.1 项目背景1.2 LoRA和 QLoRA 简介1.3 LLaMA 架构和 Qwen 架构LLaM ...
- flutter-超出部分隐藏
第一种写法 1 ConstrainedBox( 2 constraints: BoxConstraints( 3 maxHeight: 100 4 ), 5 child: Stack( 6 overf ...
- AI探索:通过宏脚本给小众编辑器EverEdit插上AI的翅膀!
1 AI探索:通过宏脚本给小众编辑器EverEdit插上AI的翅膀! 1.1 背景 在AI编程大行其道的背景下,各种AI编程工具:Cursor.VSCode的各种插件.Trae等等搞得不亦乐乎!您 ...