博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
diamond源码阅读-目录监控
阅读量:6872 次
发布时间:2019-06-26

本文共 7680 字,大约阅读时间需要 25 分钟。

  hot3.png

PathNode(Path)

StandardWatchEventKind(WatchEvent)
Watchable(WatchKey WatchService WatchEvent)
WatchKey(PathNode WatchEvent WatchService)
WatchService(WatchKey Path)
WatchEvent
FileSystem(WatchService)
Path>Watchable
WatchEvent
StandardWatchEventKind(ENTRY_CREATE; ENTRY_DELETE; ENTRY_MODIFY; OVERFLOW)
WatchService  WatchKey
WatchService
1 register 注册监视目录 ,生成watchedKey(遍历子目录,每个文件都注册一个事件),添加到watchedKeys

  1.1

public WatchKey register(Path root, boolean fireCreatedEventOnIndex, WatchEvent.Kind
... events) { if (events == null || events.length == 0) throw new UnsupportedOperationException("null events"); if (this.service.isShutdown()) throw new IllegalStateException("服务已经关闭"); if (!root.exists()) throw new IllegalArgumentException("监视的目录不存在"); WatchKey key = new WatchKey(root, this, fireCreatedEventOnIndex, events); resetKey(key); return key; }

 1.1.1 WatchKey

public WatchKey(final Path path, final WatchService watcher, boolean fireCreatedEventOnIndex, WatchEvent.Kind
... events) { valid = true; this.watcher = watcher; // 建立内存索引 this.root = new PathNode(path, true); if (events != null) { for (WatchEvent.Kind
event : events) { filterSet.add(event); } } LinkedList
> changedEvents = new LinkedList
>(); index(this.root, fireCreatedEventOnIndex, changedEvents); this.changedEvents = changedEvents; }

  1.1.1.1 WatchKey  为每个目录下子文件建立一个ENTRY_CREATE 监听事件

private void index(PathNode node, boolean fireCreatedEventOnIndex, LinkedList
> changedEvents) { File file = node.getPath().getFile(); if (!file.isDirectory()) { return; } File[] subFiles = file.listFiles(); if (subFiles != null) { for (File subFile : subFiles) { PathNode subNode = new PathNode(new Path(subFile), false); if (fireCreatedEventOnIndex) { changedEvents.add(new WatchEvent
(StandardWatchEventKind.ENTRY_CREATE, 1, subNode.getPath())); } node.addChild(subNode); if (subNode.getPath().isDirectory()) { index(subNode, fireCreatedEventOnIndex, changedEvents); } } } }

2  启动的一个线程,定时扫描watchedKeys,调用watchedKey.check(),

  如果有变化,watchedKeys 删掉watchedKey ,changedKeys add watchedKey

  

public WatchService(long checkInterval) { service = Executors.newSingleThreadScheduledExecutor(); service.scheduleAtFixedRate(new CheckThread(), checkInterval, checkInterval, TimeUnit.MILLISECONDS); }
private final class CheckThread implements Runnable { public void run() { check(); } } /** * 主动check */    public void check() { synchronized (this) { Iterator
it = watchedKeys.iterator(); while (it.hasNext()) { WatchKey key = it.next(); try { if (key.check()) { changedKeys.add(key); it.remove(); } } catch (Throwable t) { log.error("检测WatchKey异常,key=" + key, t); } } } }

 2.1 key.check()

  

boolean check() { if (this.changedEvents != null && this.changedEvents.size() > 0) return true; if (!this.valid) return false; List
> list = new LinkedList
>(); if (check(root, list)) { this.changedEvents = list; return true; } else { return false; } }

2.1.1

  

private boolean check(PathNode node, List
> changedEvents) { Path nodePath = node.getPath(); File nodeNewFile = new File(nodePath.getAbsolutePath()); if (nodePath != null) { if (node.isRoot()) { if (!nodeNewFile.exists()) return fireOnRootDeleted(changedEvents, nodeNewFile);//触发删除事件,添加到当前watchedKey的changedEvents else { return checkNodeChildren(node, changedEvents, nodeNewFile); } } else { return checkNodeChildren(node, changedEvents, nodeNewFile); } } else throw new IllegalStateException("PathNode没有path"); }

2.1.1.1 监听新增事件 修改事件,若有讲事件添加到当前watchedKey的changedEvents

private boolean checkNodeChildren(PathNode node, List
> changedEvents, File nodeNewFile) { boolean changed = false; Iterator
it = node.getChildren().iterator(); // 用于判断是否有新增文件或者目录的现有名称集合 Set
childNameSet = new HashSet
(); while (it.hasNext()) { PathNode child = it.next(); Path childPath = child.getPath(); childNameSet.add(childPath.getName()); File childNewFile = new File(childPath.getAbsolutePath()); // 1、判断文件是否还存在 if (!childNewFile.exists() && filterSet.contains(StandardWatchEventKind.ENTRY_DELETE)) { changed = true; changedEvents.add(new WatchEvent
(StandardWatchEventKind.ENTRY_DELETE, 1, childPath)); it.remove();// 移除节点 } // 2、如果是文件,判断是否被修改 if (childPath.isFile()) { if (checkFile(changedEvents, child, childNewFile) && !changed) { changed = true; } } // 3、递归检测目录 if (childPath.isDirectory()) { if (check(child, changedEvents) && !changed) { changed = true; } } } // 查看是否有新增文件 File[] newChildFiles = nodeNewFile.listFiles(); if(newChildFiles!=null) for (File newChildFile : newChildFiles) { if (!childNameSet.contains(newChildFile.getName()) && filterSet.contains(StandardWatchEventKind.ENTRY_CREATE)) { changed = true; Path newChildPath = new Path(newChildFile); changedEvents.add(new WatchEvent
(StandardWatchEventKind.ENTRY_CREATE, 1, newChildPath)); PathNode newSubNode = new PathNode(newChildPath, false); node.addChild(newSubNode);// 新增子节点 // 如果是目录,递归调用 if (newChildFile.isDirectory()) { checkNodeChildren(newSubNode, changedEvents, newChildFile); } } } return changed; }

 

3 如何使用

private void startCheckLocalDir(final String filePath) { final WatchService watcher = FileSystem.getDefault().newWatchService(); Path path = new Path(new File(filePath)); // 注册事件        watcher.register(path, true, StandardWatchEventKind.ENTRY_CREATE, StandardWatchEventKind.ENTRY_DELETE, StandardWatchEventKind.ENTRY_MODIFY); // 第一次运行,主动check checkAtFirst(watcher); singleExecutor.execute(new Runnable() { public void run() { log.debug(">>>>>>已经开始监控目录<<<<<<"); // 无限循环等待事件                while (isRun) { // 凭证 WatchKey key; try { key = watcher.take(); } catch (InterruptedException x) { continue; } // reset,如果无效,跳出循环,无效可能是监听的目录被删除                    if (!processEvents(key)) { log.error("reset unvalid,监控服务失效"); break; } } log.debug(">>>>>>退出监控目录<<<<<<"); watcher.close(); } }); }

3.1 处理触发的事件,并继续监听

/** * 处理触发的事件 * * @param key * @return     */ @SuppressWarnings({ "unchecked" }) private boolean processEvents(WatchKey key) { /** * 获取事件集合 */        for (WatchEvent
event : key.pollEvents()) { // 事件的类型 // WatchEvent.Kind
kind = event.kind(); // 通过context方法得到发生事件的path WatchEvent
ev = (WatchEvent
) event; Path eventPath = ev.context(); String realPath = eventPath.getAbsolutePath(); if (ev.kind() == StandardWatchEventKind.ENTRY_CREATE || ev.kind() == StandardWatchEventKind.ENTRY_MODIFY) { String grandpaDir = null; try { grandpaDir = FileUtils.getGrandpaDir(realPath); } catch (Exception e1) { } if (!Constants.BASE_DIR.equals(grandpaDir)) { log.error("无效的文件进入监控目录: " + realPath); continue; } existFiles.put(realPath, System.currentTimeMillis()); if (log.isInfoEnabled()) { log.info(realPath + "文件被添加或更新"); } } else if (ev.kind() == StandardWatchEventKind.ENTRY_DELETE) { String grandpaDir = null; try { grandpaDir = FileUtils.getGrandpaDir(realPath); } catch (Exception e1) { } if (Constants.BASE_DIR.equals(grandpaDir)) { // 删除的是文件 existFiles.remove(realPath); if (log.isInfoEnabled()) { log.info(realPath + "文件被被删除"); } } else { // 删除的是目录 Set
keySet = new HashSet
(existFiles.keySet()); for (String filePath : keySet) { if (filePath.startsWith(realPath)) { existFiles.remove(filePath); if (log.isInfoEnabled()) { log.info(filePath + "文件被删除"); } } } } } } return key.reset();//WatchService 继续监听 }

 

转载于:https://my.oschina.net/sbcagf/blog/783054

你可能感兴趣的文章
让任正非陷入“迷茫”的,不只是华为……
查看>>
Django性能测试—一个现实世界的例子
查看>>
中国光伏组件反补贴税下调1.32%
查看>>
Cray推出开源大数据一体机Urika-GX
查看>>
智能门锁市场“钱途”无限 把关智能家居入口
查看>>
大数据项目产品选型的五个建议
查看>>
云数据加密公司LOCKet获千万级Pre-A融资
查看>>
爱尔兰WElink Energy宣布在葡萄牙建立220MW太阳能光伏项目
查看>>
如何从敏捷到精益地修复bug与解决问题
查看>>
开启智慧新生活 新余市智慧城市建设全省率先
查看>>
智慧东湖让城市慢游更幸福
查看>>
陕西联通推进高速公路WiFi覆盖
查看>>
PHP开发者常犯的10个MySQL错误
查看>>
物联网在交通领域示范应用的三大趋势
查看>>
浅谈如何用Java操作MongoDB?
查看>>
Java ConcurrentModificationException异常原因和解决方法
查看>>
2015 年对 GitLab 来说是非常棒的一年
查看>>
《编写高质量代码:改善c程序代码的125个建议》——建议17-1:先处理正常情况,再处理异常情况...
查看>>
《Docker技术入门与实战》——3.2 查看镜像信息
查看>>
RoboVM 被 Xamarin 收购,不再开源
查看>>