WatchService递归监听目录的文件更新

优点

用WatchService对本地文件的监控,WatchService是基于本机操作系统实现对文件的监控,动态获取文件变化。添加自动回调函数,自定义处理方法

 jdk版本

WatchService是jdk1.7版本引进的,位于nio包下

  1 package aws;
  2 
  3 
  4 import org.apache.log4j.Logger;
  5 
  6 import java.io.File;
  7 import java.io.FilenameFilter;
  8 import java.nio.file.*;
  9 import java.util.concurrent.Executors;
 10 import java.util.regex.Pattern;
 11 
 12 public class FileWatchUtil {
 13     public static void main(String[] args) throws Exception {
 14 
 15         FileWatchUtil.CallBack callBack = new FileWatchUtil.CallBack() {
 16             @Override
 17             public void CallBackMethod(String path) {
 18                 System.out.println("Hello Call Back ===>" + path);
 19             }
 20         };
 21         new FileWatchUtil("D:\\data\\", "test").setCallBack(callBack);
 22 
 23     }
 24 
 25 
 26     private String fileDirectory;
 27     private String nameRule;
 28     private CallBack callBack;
 29     private static Logger logger = Logger.getLogger("CONSOLE");
 30 
 31     /**
 32      * 构造函数
 33      */
 34     public FileWatchUtil(String fileDirectory, String nameRule) {
 35         this.fileDirectory = fileDirectory;
 36         this.nameRule = nameRule;
 37     }
 38 
 39     /**
 40      * 回调函数接口
 41      *
 42      * @author Administrator
 43      */
 44     public static interface CallBack {
 45         void CallBackMethod(String path);
 46     }
 47 
 48     /**
 49      * 设置回调函数
 50      */
 51 
 52     public void setCallBack(CallBack cb) {
 53         callBack = cb;
 54         if (callBack != null) {
 55             logger.info("----callBack class==>" + callBack.toString());
 56             run();
 57         }
 58     }
 59 
 60     public void run() {
 61         Path path = Paths.get(fileDirectory);
 62         if (!Files.exists(path)) {
 63             logger.info("----监听目录不存在!");
 64             System.exit(0);
 65         }
 66         // 根目录添加监听
 67         watchDir(fileDirectory);
 68         // 迭代扫描子目录并添加监听
 69         findFilesPathAndWatch(fileDirectory);
 70     }
 71 
 72     private void findFilesPathAndWatch(String watchPath) {
 73         try {
 74             File rootFile = new File(watchPath);
 75             if (rootFile.isDirectory()) {
 76                 String regex = nameRule; // 文件夹命名筛选规则
 77                 String path = watchPath;
 78                 FilenameFilter fileFilter = new FilenameFilter() {
 79                     public boolean accept(File dir, String name) {
 80                         // 文件名规则过滤
 81                         if (Pattern.matches(regex, name)) {
 82                             return false;
 83                         }
 84                         // 判断是否是文件夹
 85                         if (new File(path + File.separator + name).isDirectory()) {
 86                             return true;
 87                         }
 88                         return false;
 89                     }
 90                 };
 91                 // ----文件筛选规则-----
 92                 File[] files = rootFile.listFiles(fileFilter);
 93                 for (File file : files) {
 94                     // 如果这个文件是目录,则进行递归搜索
 95                     if (file.isDirectory()) {
 96                         String newPath = file.getPath();
 97                         // 迭代查找文件目录
 98                         findFilesPathAndWatch(newPath);
 99                         // logger.info("--find path:" + newPath);
100                         // 添加文件监听
101                         watchDir(newPath);
102                     }
103                 }
104             }
105         } catch (Exception e) {
106             e.printStackTrace();
107             logger.error("----findFilesPathAndWatch error----: " + e.getMessage());
108         }
109     }
110 
111     private void watchDir(String watchDir) {
112         try {
113             //获取当前文件系统的监控对象
114             WatchService service = FileSystems.getDefault().newWatchService();
115             // logger.info("----create watch service----");
116             //获取文件目录下的Path对象注册到 watchService中。 监听的事件类型,有创建,删除,以及修改
117             Paths.get(watchDir).register(service, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY);
118             // logger.info("----register listening type----");
119             // 新建线程添加监听
120             Executors.newSingleThreadExecutor().submit(WatchServiceRun(service, watchDir));
121         } catch (Exception e) {
122             e.printStackTrace();
123             logger.error("----watchDir error----: " + e.getMessage());
124         }
125     }
126 
127     private Runnable WatchServiceRun(WatchService service, String watchDir) {
128         Runnable runnable = new Runnable() {
129             @Override
130             public void run() {
131                 Long id = Thread.currentThread().getId();
132                 logger.info(id + "--> watch path:" + watchDir);
133                 while (true) {
134                     try {
135                         // 获取可用key.没有可用的就wait
136                         WatchKey key = service.take();
137                         logger.info(id + "--> key" + key);
138                         for (WatchEvent<?> event : key.pollEvents()) {
139                             if (event.context() == null) {
140                                 continue;
141                             }
142 
143                             // 判断监听的目录是否存在
144                             if (Files.notExists(Paths.get(watchDir))) {
145                                 logger.info(id + "--> 监听目录名称已经修改:-->" + watchDir);
146                                 break;
147                             }
148 
149                             String handleType = event.kind().toString();
150                             String path = watchDir + File.separator + event.context();
151                             // 判断子文件是否存在
152                             if (Files.notExists(Paths.get(path))) {
153                                 logger.info(id + "--> 子文件已经删除(文件或目录): " + path + "  类型:" + handleType + "  次数: " + event.count());
154                                 continue;
155                             }
156                             // 判断子文件类型是否是目录
157                             if (Files.isDirectory(Paths.get(path))) {
158                                 // 只监听目录新增
159                                 if ("ENTRY_CREATE".equals(handleType)) {
160                                     logger.info(id + "--> 新曾子目录: " + path + "  类型:" + handleType + "  次数: " + event.count());
161                                     watchDir(path);
162                                 }
163                             } else {
164                                 logger.info(id + "--> 新增子文件: " + path + "  类型:" + handleType + "  次数: " + event.count());
165                                 // 回调自定义处理函数
166                                 callBack.CallBackMethod(path);
167                             }
168                         }
169                         // 重置,这一步很重要,否则当前的key就不再会获取将来发生的事件
170                         boolean valid = key.reset();
171                         //失效状态,退出监听
172                         if (!valid) {
173                             // 监听目录删除后,退出目录监听
174                             logger.info(id + "--> 退出目录监听:" + watchDir);
175                             break;
176                         }
177                         // 判断目录是否存在,取消监听
178                         if (Files.notExists(Paths.get(watchDir))) {
179                             // 监听目录名称已经修改后取消原来的目录监听
180                             logger.info(id + "--> 取消目录监听:" + watchDir);
181                             break;
182                         }
183                     } catch (Exception e) {
184                         e.printStackTrace();
185                         logger.error("----watchDir error----: " + e.getMessage());
186                         break;
187                     }
188                 }
189             }
190         };
191         return runnable;
192     }
193 
194 
195 }
View Code

 

 

问题:

1. 自动循环添加监听 ==》 已解决

2. WatchService,重复触发Modify事件 (使用notepad ++编辑文件的话或触发两次 ENTRY_MODIFY监听,使用记事本则不会重复触发) ==》 未解决

3. 监听到文件变化时,自动回调 ==》已解决

posted @ 2021-12-14 16:12  風巽千龍  阅读(280)  评论(0)    收藏  举报