本文目录导读:

- 使用Java NIO的WatchService(推荐)
- 增强版:递归监控子目录
- 使用Apache Commons IO
- 使用Java的File.lastModified()轮询(基础方法)
- 实际应用:配置文件监控器
- 性能对比和选择建议
我来介绍几种Java实现文件监控的方法,从基础到高级:
使用Java NIO的WatchService(推荐)
这是Java 7+官方推荐的文件监控方式:
import java.io.IOException;
import java.nio.file.*;
import java.util.List;
public class FileWatcherExample {
public static void main(String[] args) throws IOException, InterruptedException {
// 监控的目录
Path dir = Paths.get("/path/to/monitor");
// 创建WatchService
WatchService watchService = FileSystems.getDefault().newWatchService();
// 注册监控事件
dir.register(watchService,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);
System.out.println("开始监控目录: " + dir.toAbsolutePath());
// 循环处理事件
while (true) {
WatchKey key = watchService.take(); // 阻塞等待
List<WatchEvent<?>> events = key.pollEvents();
for (WatchEvent<?> event : events) {
WatchEvent.Kind<?> kind = event.kind();
Path filename = (Path) event.context();
if (kind == StandardWatchEventKinds.OVERFLOW) {
continue;
}
if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
System.out.println("文件创建: " + filename);
} else if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
System.out.println("文件删除: " + filename);
} else if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {
System.out.println("文件修改: " + filename);
}
}
// 重置WatchKey
boolean valid = key.reset();
if (!valid) {
break;
}
}
watchService.close();
}
}
增强版:递归监控子目录
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;
public class RecursiveFileWatcher {
private final WatchService watchService;
private final Map<WatchKey, Path> keyPathMap = new HashMap<>();
public RecursiveFileWatcher() throws IOException {
this.watchService = FileSystems.getDefault().newWatchService();
}
// 递归注册所有子目录
private void registerDirectory(Path dir) throws IOException {
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
WatchKey key = dir.register(watchService,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);
keyPathMap.put(key, dir);
System.out.println("监控目录: " + dir);
return FileVisitResult.CONTINUE;
}
});
}
public void startMonitoring(Path rootDir) throws IOException, InterruptedException {
registerDirectory(rootDir);
while (true) {
WatchKey key = watchService.take();
Path dir = keyPathMap.get(key);
if (dir == null) continue;
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
Path filename = (Path) event.context();
Path fullPath = dir.resolve(filename);
if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
System.out.println("创建: " + fullPath);
// 如果是新创建的目录,也要注册监控
if (Files.isDirectory(fullPath)) {
registerDirectory(fullPath);
}
} else if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
System.out.println("删除: " + fullPath);
} else if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {
System.out.println("修改: " + fullPath);
}
}
if (!key.reset()) {
keyPathMap.remove(key);
if (keyPathMap.isEmpty()) break;
}
}
}
public static void main(String[] args) throws Exception {
RecursiveFileWatcher watcher = new RecursiveFileWatcher();
watcher.startMonitoring(Paths.get("/path/to/monitor"));
}
}
使用Apache Commons IO
需要添加依赖:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import java.io.File;
public class CommonsIOFileWatcher {
public static void main(String[] args) throws Exception {
// 监控目录
File directory = new File("/path/to/monitor");
// 创建文件观察器
FileAlterationObserver observer = new FileAlterationObserver(directory);
// 添加事件监听器
observer.addListener(new FileAlterationListenerAdaptor() {
@Override
public void onFileCreate(File file) {
System.out.println("文件创建: " + file.getAbsolutePath());
}
@Override
public void onFileDelete(File file) {
System.out.println("文件删除: " + file.getAbsolutePath());
}
@Override
public void onFileChange(File file) {
System.out.println("文件修改: " + file.getAbsolutePath());
}
@Override
public void onDirectoryCreate(File dir) {
System.out.println("目录创建: " + dir.getAbsolutePath());
}
@Override
public void onDirectoryDelete(File dir) {
System.out.println("目录删除: " + dir.getAbsolutePath());
}
});
// 创建监控器,设置检查间隔(毫秒)
FileAlterationMonitor monitor = new FileAlterationMonitor(1000, observer);
// 启动监控
monitor.start();
System.out.println("开始监控...");
// 运行一段时间后停止
Thread.sleep(60000);
monitor.stop();
}
}
使用Java的File.lastModified()轮询(基础方法)
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class PollingFileWatcher {
private final Map<String, Long> fileLastModifiedMap = new HashMap<>();
private volatile boolean running = true;
public void startMonitoring(String directoryPath, long interval) {
File directory = new File(directoryPath);
new Thread(() -> {
while (running) {
try {
checkDirectory(directory);
Thread.sleep(interval);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}, "File-Watcher").start();
}
private void checkDirectory(File directory) {
File[] files = directory.listFiles();
if (files == null) return;
for (File file : files) {
String path = file.getAbsolutePath();
long lastModified = file.lastModified();
Long previousModified = fileLastModifiedMap.get(path);
if (previousModified == null) {
// 新文件
System.out.println("新文件: " + path);
fileLastModifiedMap.put(path, lastModified);
} else if (previousModified != lastModified) {
// 文件被修改
System.out.println("文件修改: " + path);
fileLastModifiedMap.put(path, lastModified);
}
}
// 检查是否有文件被删除
fileLastModifiedMap.keySet().removeIf(path -> !new File(path).exists());
}
public void stop() {
this.running = false;
}
public static void main(String[] args) throws InterruptedException {
PollingFileWatcher watcher = new PollingFileWatcher();
watcher.startMonitoring("/path/to/monitor", 1000); // 每秒检查一次
Thread.sleep(60000);
watcher.stop();
}
}
实际应用:配置文件监控器
import java.io.IOException;
import java.nio.file.*;
import java.util.function.Consumer;
public class ConfigFileWatcher {
private final Path configPath;
private final Consumer<Path> onFileChange;
private Thread watchThread;
public ConfigFileWatcher(String configFilePath, Consumer<Path> onFileChange) {
this.configPath = Paths.get(configFilePath).toAbsolutePath();
this.onFileChange = onFileChange;
}
public void start() throws IOException {
Path parentDir = configPath.getParent();
if (!Files.exists(parentDir)) {
Files.createDirectories(parentDir);
}
watchThread = new Thread(() -> {
try {
WatchService watchService = FileSystems.getDefault().newWatchService();
parentDir.register(watchService,
StandardWatchEventKinds.ENTRY_MODIFY);
System.out.println("开始监控配置文件: " + configPath);
while (!Thread.currentThread().isInterrupted()) {
WatchKey key = watchService.take();
for (WatchEvent<?> event : key.pollEvents()) {
Path changedFile = (Path) event.context();
Path fullPath = parentDir.resolve(changedFile);
if (fullPath.equals(configPath)) {
System.out.println("配置文件已修改: " + configPath);
onFileChange.accept(configPath);
}
}
if (!key.reset()) break;
}
watchService.close();
} catch (IOException | InterruptedException e) {
Thread.currentThread().interrupt();
}
}, "Config-Watcher");
watchThread.setDaemon(true);
watchThread.start();
}
public void stop() {
if (watchThread != null) {
watchThread.interrupt();
}
}
// 使用示例
public static void main(String[] args) throws IOException {
ConfigFileWatcher watcher = new ConfigFileWatcher(
"/etc/myapp/config.properties",
path -> {
System.out.println("重新加载配置...");
// 重新加载配置文件的逻辑
}
);
watcher.start();
// 添加关闭钩子
Runtime.getRuntime().addShutdownHook(new Thread(watcher::stop));
}
}
性能对比和选择建议
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| WatchService | 实时性高,资源消耗低 | 部分系统支持有限 | 大多数文件监控需求 |
| Apache Commons IO | 功能完善,易用性好 | 需要外部依赖 | 需要高级功能的项目 |
| 轮询方式 | 简单直接,兼容性好 | 延迟高,资源消耗大 | 简单场景或旧系统 |
最佳实践建议:
- 首选使用Java NIO的WatchService
- 对于生产环境,考虑使用成熟的框架如Apache Commons IO或JNotify
- 监控配置文件的变更是最常见的应用场景
- 注意处理WatchEvent.OVERFLOW事件,表示可能丢失事件
这些示例涵盖了文件监控的主要实现方式,你可以根据具体需求选择合适的方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播