Java 中文件目录监听实现(java监听ftp目录)
目录监听实现目前主要有两种实现,一种是 java 7 自带的 API ,另一种是 apache commons-io 类库实现。
SDK watch监控
采用 SDK API watch 实现目录变化。
- 可以监听目录下的文件新增、删除、变更
- 目录下文件名变更会收到一条删除,一条新增消息
- 目录下的子目录可以得到监听,即子目录下的文件发生新增、删除会得到目录变更的通知
- 只能得到目录发生了变化的通知,无法知道目录下那些文件发生了变化
- 子目录下的文件内容发生变化不会得到消息通知
注:com.xxx.common.util.Assert 可以用 apache-common 中的,功能实现一样
import com.xxx.common.util.Assert;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.file.*;
import java.util.concurrent.TimeUnit;
import static java.nio.file.StandardWatchEventKinds.*;
/**
* java 7 实现文件目录监听,能够实现文件目录的新增、变更、删除;
* 1、修改文件名时,会收到一次删除,一次新增事件
* 2、可以监控子目录变化,但无法监控子目录中文件的变化(子目录下文件内容发生变化时不会触发监听事件)
*
* @author: zhangql
* @create: 2023/3/17 9:08
**/
@Slf4j
public class SdkDirectoryWatch implements Runnable {
private String fileDirectory;
public SdkDirectoryWatch(String fileDirectory) {
Assert.notEmpty(fileDirectory, "fileDirectory is null");
this.fileDirectory = fileDirectory;
}
@Override
public void run() {
WatchService watchService = null;
try {
watchService = FileSystems.getDefault().newWatchService();
//监听文件目录
Paths.get(fileDirectory)
//注册监听事件
.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
}
catch (IOException e) {
log.error("注册监听器异常", e);
}
while(!Thread.currentThread().isInterrupted()) {
WatchKey watchKey = null;
try {
watchKey = watchService.take();
}
catch (InterruptedException e) {
log.warn("线程被中断,退出监听");
break;
}
for (WatchEvent<?> pollEvent : watchKey.pollEvents()) {
log.debug("{} 文件: {}, 次数:{}", pollEvent.context(), pollEvent.kind(), pollEvent.count());
}
//重置状态(当前 Key 就不会再获取将来发生的事件)
boolean valid = watchKey.reset();
//失效状态,退出监听
if (!valid) {
break;
}
}
}
public static void main(String[] args) throws InterruptedException {
String directory = "D:\\Temp\\images";
Runnable runnable = new SdkDirectoryWatch(directory);
Thread thread = new Thread(runnable);
thread.start();
Thread.sleep(TimeUnit.SECONDS.toMillis(30));
thread.interrupt();
}
}
控制台信息
10:39:31.623 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - ~建 XLSX 工作表.tmp 文件: ENTRY_CREATE, 次数:1
10:39:31.624 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - ~建 XLSX 工作表.tmp 文件: ENTRY_MODIFY, 次数:1
10:39:31.625 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - ~建 XLSX 工作表.tmp 文件: ENTRY_MODIFY, 次数:1
10:39:31.625 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - ~建 XLSX 工作表.tmp 文件: ENTRY_MODIFY, 次数:2
10:39:31.626 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - ~建 XLSX 工作表.tmp 文件: ENTRY_MODIFY, 次数:1
10:39:31.627 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - ~建 XLSX 工作表.tmp 文件: ENTRY_MODIFY, 次数:1
10:39:31.627 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - 新建 XLSX 工作表.xlsx~RFab854c4.TMP 文件: ENTRY_CREATE, 次数:1
10:39:31.629 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - 新建 XLSX 工作表.xlsx~RFab854c4.TMP 文件: ENTRY_DELETE, 次数:1
10:39:31.629 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - 新建 XLSX 工作表.xlsx 文件: ENTRY_DELETE, 次数:1
10:39:31.629 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - 新建 XLSX 工作表.xlsx~RFab854c4.TMP 文件: ENTRY_CREATE, 次数:1
10:39:31.630 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - ~建 XLSX 工作表.tmp 文件: ENTRY_DELETE, 次数:1
10:39:31.630 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - 新建 XLSX 工作表.xlsx 文件: ENTRY_CREATE, 次数:1
10:39:31.630 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - 新建 XLSX 工作表.xlsx 文件: ENTRY_MODIFY, 次数:1
10:39:31.630 [Thread-0] DEBUG com.xxx.base.directory.watch.SdkDirectoryWatch - 新建 XLSX 工作表.xlsx~RFab854c4.TMP 文件: ENTRY_DELETE, 次数:1
部份文件的变更会收到多条记录。比如在目录下创建一个 Excel 文件,收到的消息如上面消息所示。
Apache Commons-io 监控
FileListener
package com.xxx.base.directory.watch.apache;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import java.io.File;
/**
* @author: zhangql
* @create: 2023/3/17 9:47
**/
@Slf4j
public class FileListener extends FileAlterationListenerAdaptor {
public FileListener() {
super();
}
@Override
public void onStart(FileAlterationObserver observer) {
super.onStart(observer);
}
@Override
public void onDirectoryCreate(File directory) {
log.debug("创建目录:{}", directory.getAbsolutePath());
}
@Override
public void onDirectoryChange(File directory) {
log.debug("变更目录:{}", directory.getAbsolutePath());
}
@Override
public void onDirectoryDelete(File directory) {
log.debug("删除目录:{}", directory.getAbsolutePath());
}
@Override
public void onFileCreate(File file) {
log.debug("创建文件:{}", file.getAbsolutePath());
}
@Override
public void onFileChange(File file) {
log.debug("文件变更:{}", file.getAbsolutePath());
}
@Override
public void onFileDelete(File file) {
log.debug("文件删除:{}", file.getAbsolutePath());
}
@Override
public void onStop(FileAlterationObserver observer) {
super.onStop(observer);
}
}
ApacheDirectoryWatch
package com.xxx.base.directory.watch.apache;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.HiddenFileFilter;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import java.io.File;
import java.util.concurrent.TimeUnit;
/**
* 与 SDK 监听基本类似
* @author: zhangql
* @create: 2023/3/17 9:51
**/
public class ApacheDirectoryWatch {
public static void main(String[] args) throws Exception {
String directory = "D:\\Temp\\images";
//轮询时间
long interval = TimeUnit.SECONDS.toMillis(5);
//目录过滤器
IOFileFilter directoryFilter = FileFilterUtils.and(
FileFilterUtils.directoryFileFilter(), HiddenFileFilter.VISIBLE
);
//文件过滤器
IOFileFilter fileFilter = FileFilterUtils.and(
FileFilterUtils.fileFileFilter(), FileFilterUtils.suffixFileFilter(".png")
);
IOFileFilter filter = FileFilterUtils.or(directoryFilter, fileFilter);
//使用过滤器
FileAlterationObserver observer = new FileAlterationObserver(new File(directory), filter);
//不使用过虑器
//FileAlterationObserver observer = new FileAlterationObserver(new File(directory));
observer.addListener(new FileListener());
//创建文件监听器
FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);
monitor.start();
}
}
实现功能基本和 SDK API 相同,在 SDK API 基础上增加了文件类型的过滤。
控制台信息
10:39:32.236 [Thread-0] DEBUG com.xxx.base.directory.watch.apache.FileListener - 创建文件:D:\Temp\images\新建 XLSX 工作表.xlsx
10:40:05.988 [Thread-0] DEBUG com.xxx.base.directory.watch.apache.FileListener - 创建文件:D:\Temp\images\新建文本文档.txt
Apache Commons-io 采用轮询