Java 中文件目录监听实现(java监听ftp目录)

createh53个月前 (12-30)技术教程50

目录监听实现目前主要有两种实现,一种是 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 采用轮询

相关文章

纯小白干货:Java import以及Java类的搜索路径

如果你希望使用Java包中的类,就必须先使用import语句导入。import语句与C语言中的 #include 有些类似,语法为: import package1[.package2…].class...

Java路径-37-Java的Iterator(java路径是什么意思)

1 Iterator的概念在Java中,如果我们需要遍历一个集合(Collection)或者数组(Array),我们通常会使用for循环来遍历。但是,当我们需要在遍历的过程中修改集合或者数组时,这种方...

我的世界Java路径设置攻略(我的世界java路径怎么设置)

我的世界Java路径设置攻略带给玩家,我的世界这款游戏在玩之前需要先设置Java路径,Java路径在哪,看看我的世界Java路径设置攻略。我的世界java路径设置攻略:1、首先我们要确保电脑中已经下载...

我的世界启动器Java路径如何设置(我的世界官方启动器java路径)

这次搞趣网小编为诸位我的世界PC端玩家带来的是我的世界启动器Java路径如何设置攻略,希望诸位我的世界玩家会喜欢。我的世界java路径设置攻略:1、首先我们要确保电脑中已经下载并安装好了最新的java...

java实现大文件的分片上传与下载(java大文件上传解决方案)

java实现大文件的分片上传与下载,java实现大文件的分片上传与下载解决方案,java实现大文件的分片上传与下载思路,java实现大文件的分片上传与下载源码,java实现大文件的分片上传与下载实例,...

java创建文件夹的4种方法及其优缺点 最全面总结

本文为大家介绍Java IO-创建文件夹的四种方法,及其优缺点的解析。如果您阅读完成,觉得此文对您有帮助,请给我点个赞,您的支持是我不竭的创作动力。1.传统API创建文件夹方式Java传统的IO AP...