应用场景:

代码可以实现文件变化后的监听,如文件变化,自动重新加载文件内容,实现配置文件的热部署。

代码:

package com.yx.demo.filemonitor;import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;/*** FileMonitor* 文件监控器** @author yx* @date 2019/12/21 0:59*/
public class FileMonitor {/*** 每2秒更新的默认监控器*/private static FileMonitor defaultFileMonitor = new FileMonitor(2 * 1000);private Timer timer_;private HashMap<File, FileEntry> files_; // File -> Longprivate List<FileEntry> fileEntrys = new java.util.concurrent.CopyOnWriteArrayList<FileEntry>();private Collection<WeakReference<FileListener>> listeners_; // of WeakReference(FileListener)private long pollingInterval = 10000;public static FileMonitor getDefaultFileMonitor() {return defaultFileMonitor;}/*** Create a file monitor instance with specified polling interval.** @param pollingInterval Polling interval in milli seconds.*/public FileMonitor(long pollingInterval) {this.pollingInterval = pollingInterval;files_ = new HashMap<File, FileEntry>();listeners_ = new ArrayList<WeakReference<FileListener>>();timer_ = new Timer("FileMonitor", true);timer_.schedule(new FileMonitorNotifier(), 0, pollingInterval);}/*** Stop the file monitor polling.*/public void stop() {timer_.cancel();timer_ = null;}public void start() {if (timer_ == null) {timer_ = new Timer(true);timer_.schedule(new FileMonitorNotifier(), 0, pollingInterval);}}/*** Add file to listen for. File may be any java.io.File (including a* directory) and may well be a non-existing file in the case where the* creating of the file is to be trepped.* <p>* More than one file can be listened for. When the specified file is* created, modified or deleted, listeners are notified.** @param file File to listen for.*/public void addFile(String id, File file) {if (!files_.containsKey(file)) {FileEntry entry = new FileEntry(id, file, file.exists() ? file.lastModified() : -1);files_.put(file, entry);}}/*** 添加监控文件实体。** @param fileEntry*/public void addFileEntry(FileEntry fileEntry) {if (!fileEntrys.contains(fileEntry)) {fileEntrys.add(fileEntry);}}/*** 通过文件实体的标识判断监控文件实体是否存在。** @param id* @return*/public boolean fileEntryExists(String id) {if (id == null) {return false;}for (int i = 0; i < fileEntrys.size(); i++) {if (id.equals(fileEntrys.get(i).getId())) {return true;}}return false;}/*** 通过文件实体标识删除一个监控文件实体。** @param id*/public void removeFileEntry(String id) {if (id == null) {return;}for (int i = 0; i < fileEntrys.size(); i++) {if (id.equals(fileEntrys.get(i).getId())) {fileEntrys.remove(i);return;}}}/*** Remove specified file for listening.** @param file File to remove.*/public void removeFile(File file) {files_.remove(file);}/*** Add listener to this file monitor.** @param fileListener Listener to add.*/public void addListener(FileListener fileListener) {// Don't add if its already therefor (Iterator<WeakReference<FileListener>> i = listeners_.iterator(); i.hasNext(); ) {WeakReference<FileListener> reference = i.next();FileListener listener = (FileListener) reference.get();if (listener == fileListener) {return;}}// Use WeakReference to avoid memory leak if this becomes the// sole reference to the object.listeners_.add(new WeakReference<FileListener>(fileListener));}/*** Remove listener from this file monitor.** @param fileListener Listener to remove.*/public void removeListener(FileListener fileListener) {for (Iterator<WeakReference<FileListener>> i = listeners_.iterator(); i.hasNext(); ) {WeakReference<FileListener> reference = (WeakReference<FileListener>) i.next();FileListener listener = (FileListener) reference.get();if (listener == fileListener) {i.remove();break;}}}/*** This is the timer thread which is executed every n milliseconds according* to the setting of the file monitor. It investigates the file in question* and notify listeners if changed.*/private class FileMonitorNotifier extends TimerTask {@Overridepublic void run() {try {for (Iterator<FileEntry> i = fileEntrys.iterator(); i.hasNext(); ) {try {FileEntry entry = i.next();if (entry == null || !entry.check()) {i.remove();}} catch (Throwable t) {t.printStackTrace();System.out.println("执行文件监控发生错误:" + t.getMessage());}}// Loop over the registered files and see which have changed.// Use a copy of the list in case listener wants to alter the// list within its fileChanged method.Collection<File> files = new ArrayList<File>(files_.keySet());for (Iterator<File> i = files.iterator(); i.hasNext(); ) {File file = i.next();try {FileEntry fileEntry = files_.get(file);long lastModifiedTime = fileEntry.getLastModified();long newModifiedTime = file.exists() ? file.lastModified() : -1;//logger.debug(file.getAbsolutePath());//logger.debug("    {}=>{}", lastModifiedTime, newModifiedTime);// Chek if file has changedif (newModifiedTime != lastModifiedTime) {//logger.debug("file changed {})", file.getAbsolutePath());fileEntry.setLastModified(newModifiedTime);// Register new modified timefiles_.put(file, fileEntry);if (fileEntry.getFileListener() != null) {fileEntry.getFileListener().fileChanged(fileEntry);} else {// Notify listenersfor (Iterator<WeakReference<FileListener>> j =listeners_.iterator(); j.hasNext(); ) {WeakReference<FileListener> reference =(WeakReference<FileListener>) j.next();FileListener listener = (FileListener) reference.get();// Remove from list if the back-end object has been GC'dif (listener == null) {j.remove();} else {listener.fileChanged(fileEntry);}}}}} catch (Throwable t) {if (file != null) {t.printStackTrace();System.out.println("file monitor execute error, file=" + file.getAbsolutePath() +t.getMessage());} else {System.out.println("file monitor execute error, file=null" + t.getMessage());}}}} catch (Throwable t) {System.out.println("执行文件监控发生错误" + t.getMessage());}}}
}
package com.yx.demo.filemonitor;/*** FileListener** @author yx* @date 2019/12/21 0:55*/
public interface FileListener {/*** * @param fileEntry*/public void fileChanged(FileEntry fileEntry);
}
package com.yx.demo.filemonitor;import java.io.File;
import java.lang.ref.WeakReference;/*** FileEntry* 文件Entry,如果FileEntry指定了FileListener,那么当文件发生变动时只触发指定的FileListener** @author yx* @date 2019/12/21 0:56*/
public class FileEntry {String id;File file;long lastModified;FileListener fileListener = null;Object userData;WeakReference<Object> reference = null;/*** 构造函数。** @param id* @param file*/public FileEntry(String id, File file) {this(id, file, file.exists() ? file.lastModified() : -1);}public FileEntry(Object reference, String id, File file) {this(id, file, file.exists() ? file.lastModified() : -1);reference = new WeakReference<Object>(reference);}/*** 构造函数。** @param id           标识* @param file         要监控的文件* @param lastmodified 最后修改日期*/public FileEntry(String id, File file, long lastmodified) {super();this.id = id;this.file = file;this.lastModified = lastmodified;}public boolean check() {if (reference != null && reference.get() == null) {//监控对象已经不存在,请求FileMonitor删除自己return false;}long newModifiedTime = file.exists() ? file.lastModified() : -1;if (lastModified != newModifiedTime) {this.lastModified = newModifiedTime;FileListener ls = this.getFileListener();if (ls == null) {return false;} else {try {ls.fileChanged(this);} catch (Exception e) {e.printStackTrace();System.err.println("执行文件监控事件监听" + e.getMessage());}return true;}} else {return true;}}public String getId() {return id;}public void setId(String id) {this.id = id;}public File getFile() {return file;}public void setFile(File file) {this.file = file;}public long getLastModified() {return lastModified;}public void setLastModified(long lastModified) {this.lastModified = lastModified;}public FileListener getFileListener() {return fileListener;}public void setFileListener(FileListener fileListener) {this.fileListener = fileListener;}public Object getUserData() {return userData;}public void setUserData(Object userData) {this.userData = userData;}
}

使用demo:

// 文件路径
String fileName = "conf/database.xml";// 文件监控
FileListener fileListener = new FileListener() {
@Override
public void fileChanged(FileEntry fileEntry) {
// TODO 文件变化后的业务处理
}
};File file = new File(fileName);
FileEntry fileEntry = new FileEntry("database", file);
// 设置文件监控
fileEntry.setFileListener(fileListener);FileMonitor.getDefaultFileMonitor().addFileEntry(fileEntry);

Java实现文件监控器FileMonitor相关推荐

  1. Java CSV文件读取、写入及追加

    Java CSV文件读取.写入及追加 https://blog.csdn.net/liq816/article/details/81286472 追加: FileOutputStream out = ...

  2. 一个java删除文件夹的小方法

    java删除文件夹都是从里向外删除,使用递归的方法. public class IO_FILEdemo09 {public static void main(String[] args) {// TO ...

  3. java大文件读写操作

    转载自:http://blog.csdn.net/akon_vm/article/details/7429245 RandomAccessFile RandomAccessFile是用来访问那些保存数 ...

  4. Java 查看文件绝对路径,JAVA获取文件绝对路径的方法

    本文实例讲述了JAVA获取文件绝对路径的方法.分享给大家供大家参考.具体实现方法如下: /** * 获取一个类的class文件所在的绝对路径. 这个类可以是JDK自身的类,也可以是用户自定义的类,或者 ...

  5. java编译会产生多少个类文件,编译一个定义了三个类和四个方法的Java源程序文件,总共会产生多少个字节码文件 ? ( )...

    编译一个定义了三个类和四个方法的Java源程序文件,总共会产生多少个字节码文件 ? ( ) 更多相关问题 论述风化作用基本概念及其主要类型. 什么是药用植物 学?其 研究任务是什么 ? 庐山瀑布很有名 ...

  6. cmd 将文件夹下文件剪切到另外一个文件_总结java中文件拷贝剪切的5种方式-JAVA IO基础总结第五篇...

    本文是Java IO总结系列篇的第5篇,前篇的访问地址如下: 总结java中创建并写文件的5种方式-JAVA IO基础总结第一篇 总结java从文件中读取数据的6种方法-JAVA IO基础总结第二篇 ...

  7. 创建和应用Java包文件的两种方式

    <Java编程艺术>章节选登.作者:高永强 清华大学出版社 (即将出版) 12.1  包--package       包是Java提供的文件管理机制.包把功能相似的类,按照Java的名字 ...

  8. JAVA大文件上传断点续传解决方案

    JAVA大文件上传断点续传解决方案 参考文章: (1)JAVA大文件上传断点续传解决方案 (2)https://www.cnblogs.com/songsu/p/11834425.html (3)ht ...

  9. 用Java获取文件的MD5校验和

    我正在寻找使用Java获取文件的MD5校验和. 我真的很惊讶,但是我找不到任何能显示如何获取文件的MD5校验和的东西. 怎么做? #1楼 Guava现在提供了一个新的,一致的哈希API,它比JDK中提 ...

最新文章

  1. 《2021人脸识别行业白皮书》发布 拥挤安防还有多少空间?
  2. 算法----- 下一个更大元素 I
  3. hi3559 h264
  4. Android开源音乐播放器之播放器基本功能
  5. C语言标准字符char和字符串string
  6. 4-2 父子组件的数据传递
  7. 7 大工具,驯服大数据
  8. c语言全局钩子,如何实现键盘钩子(文章)?
  9. IDEA 2017破解补丁方法
  10. 服务器ajax无响应时间,ajax 服务器响应时间
  11. 微信 小程序 APP 渗透测试方案
  12. 怎样写一个拼写检查器-贝叶斯-python
  13. 【Pytorch学习】Transforms
  14. 前端css——css三大布局模型
  15. C语言实验——一元二次方程Ⅱ
  16. 诺基亚5800XM触控音乐全解析
  17. [springboot]应用服务启动事件的监听
  18. 【四轴飞行器】【电机部分】PWM驱动空心杯转速
  19. 用单片机测量流体流速的_用AT89S52单片机怎样测流速
  20. java银行账户模拟_使用Java模拟银行账户存、取款、转账功能

热门文章

  1. 良好的沟通是团队协作的基石
  2. 寒武纪mlu-270在docker内安装驱动
  3. 超级消防员!工地现场又告急!!
  4. 除了学习PHP,还应该学什么?
  5. android获取子线程id,从onReceive android获取消息线程id或_id
  6. 突击蓝桥杯嵌入式(四)——滴答定时器、按键的三行代码消抖、LCD与ADC
  7. VUE代码在html中的哪个片段,vue渲染的数据是html片段的时候,怎么处理
  8. DB2 表Load Pending状态异常
  9. 炒股模拟神器,年化收益80%的策略是如何设计出来的!
  10. 正态分布、泊松分布和伯努利分布