JDK 之 NIO 2 WatchService、WatchKey(监控文件变化)

JDK 规范目录(https://www.cnblogs.com/binarylei/p/10200503.html)

一、WatchService、WatchKey 使用

具体详见:https://blog.csdn.net/lirx_tech/article/details/51425364

public static void main(String[] args) throws Exception {
// 1. 获取文件系统监控器,启动一个后台线程轮询
WatchService watchService = FileSystems.getDefault().newWatchService(); // 2. 注册要监听的事件类型,文件增、删、改
Paths.get("C:\\Users\\len\\Desktop\\xdr").register(watchService,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY); while (true) {
// 3. 获取准备好的事件,pool() 立即返回、take() 阻塞
WatchKey watchKey = watchService.poll(2, TimeUnit.SECONDS);
if (Objects.isNull(watchKey)) {
continue;
}
// 4. 处理准备好的事件
List<WatchEvent<?>> watchEvents = watchKey.pollEvents();
for (WatchEvent<?> event : watchEvents) {
if (event.kind().name().equals(StandardWatchEventKinds.ENTRY_CREATE.name())) {
System.out.println("create: " + event.context());
} else if (event.kind().name().equals(StandardWatchEventKinds.ENTRY_MODIFY.name())) {
System.out.println("modify: " + event.context());
} else if (event.kind().name().equals(StandardWatchEventKinds.ENTRY_DELETE.name())) {
System.out.println("delete: " + event.context());
}
}
// 5. 重启该线程,因为处理文件可能是一个耗时的过程,因此调用 pool() 时需要阻塞监控器线程
boolean valid = watchKey.reset();
if (!valid) {
break;
}
}
}

二、原理

  • AbstractWatchService 实现 WatchService 接口
  • WindowsWatchService 具体的实现,启动 Poller 线程
  • Poller 线程,轮询指定的目录

(1) AbstractWatchService

// 等待要处理的事件 signaled keys waiting to be dequeued
private final LinkedBlockingDeque<WatchKey> pendingKeys = new LinkedBlockingDeque<WatchKey>(); @Override
public final WatchKey poll(long timeout, TimeUnit unit) throws InterruptedException {
checkOpen();
WatchKey key = pendingKeys.poll(timeout, unit);
checkKey(key);
return key;
}

可以看到调用 poll 的时候直接从队列中取 key,那就必然有一个线程往 pendingKeys 中塞数据。在 AbstractWatchService 中有一个 enqueueKey 方法往 pendingKeys 中塞数据。

final void enqueueKey(WatchKey key) {
pendingKeys.offer(key);
}

(2) WindowsWatchService

AbstractWatchService 有不同的实现,以 WindowsWatchService 为例。

WindowsWatchService(WindowsFileSystem fs) throws IOException {
// create I/O completion port
long port = 0L;
try {
port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0);
} catch (WindowsException x) {
throw new IOException(x.getMessage());
}
this.poller = new Poller(fs, this, port);
this.poller.start();
}

Poller 是 WindowsWatchService 的内部类,开启了一个线程监控目录。

(3) Poller

重点关注 Poller 中的 run 方法。

@Override
public void run() {
for (;;) {
CompletionStatus info;
try {
info = GetQueuedCompletionStatus(port);
} catch (WindowsException x) {
return;
} WindowsWatchKey key = ck2key.get((int)info.completionKey());
if (key == null) {
continue;
}
boolean criticalError = false;
if (errorCode == ERROR_NOTIFY_ENUM_DIR) {
key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
} else if (errorCode != 0 && errorCode != ERROR_MORE_DATA) {
criticalError = true;
} else {
// 省略... (处理 error)
} // 一切正常则 criticalError = true,此时将这个 WatchKey 加入 pendingKeys 中
if (criticalError) {
implCancelKey(key);
key.signal();
}
}
}

参考:

  1. 《NIO.2:WatchService、WatchKey(监控文件变化)》:(https://blog.csdn.net/lirx_tech/article/details/51425364)

每天用心记录一点点。内容也许不重要,但习惯很重要!

JDK 之 NIO 2 WatchService、WatchKey(监控文件变化)的更多相关文章

  1. 利用WatchService监听文件变化

    在实现配置中心的多种方案中,有基于JDK7+的WatchService方法,其在单机应用中还是挺有实践的意义的. 代码如下: package com.longge.mytest; import jav ...

  2. Python监控文件变化:watchdog

    Python监控文件变化有两种库:pyinotify和watchdog.pyinotify依赖于Linux平台的inotify,后者则对不同平台的的事件都进行了封装.也就是说,watchdog跨平台. ...

  3. mac 监控文件变化并重启php

    自己撸一个框架,需要监控代码变化 安装fswatch brew install fswatch shell重启PHP脚本reload.sh #!/bin/sh do ps -ef | grep php ...

  4. linux 监控文件变化

    介绍 有时候我们常需要当文件变化的时候便触发某些脚本操作,比如说有文件更新了就同步文件到远程机器.在实现这个操作上,主要用到两个工具,一个是rsync,一个是inotifywait .inotifyw ...

  5. inotifywait命令如何监控文件变化?

    转载自:https://segmentfault.com/a/1190000038351925 文件监控可以配合rsync实现文件自动同步,例如监听某个目录,当文件变化时,使用rsync命令将变化的文 ...

  6. Gulp-前端进阶A-3---如何不刷新监控文件变化?

    npm install --save-dev gulp-connect npm install --save-dev gulp-livereload npm其他,前面已有 var gulp = req ...

  7. 使用apache common-io 监控文件变化--转

    package common.io; import org.apache.commons.io.filefilter.FileFilterUtils; import org.apache.common ...

  8. 利用nodejs监控文件变化并使用sftp上传到服务器

    很久没写博客了,因为最近在用react+express做一个自己的工具型网站(其实就是夺宝岛抢拍器) 然后因为经常要改动,而且又要放到服务器上进行测试.总是要webpack,然后手动把文件上传上去,不 ...

  9. 使用apache common-io 监控文件变化

    package common.io; import org.apache.commons.io.filefilter.FileFilterUtils; import org.apache.common ...

随机推荐

  1. Codeforces Round #499 (Div. 2) C Fly题解

    题目 http://codeforces.com/contest/1011/problem/C Natasha is going to fly on a rocket to Mars and retu ...

  2. zabbix 利用python脚本实现钉钉告警

    Zabbix 利用python脚本实现钉钉告警 1.安装python3.6环境 2.创建python脚本 cd local/zabbix-4.0.3/share/zabbix/alertscripts ...

  3. DNS隧道 iodns

    通过iodns这个工具也能搭建DNS隧道 iodns的优点: 对下行数据不进行编码,速度快 支持多平台 最大16个并发连接 强制密码设定 iodns创建的DNS隧道网段不能喝服务器,客户端同一网段,比 ...

  4. python 取当前日期

    import time time.strftime('%Y-%m-%d',time.localtime(time.time()))

  5. 解决VMware下CentOS连不上网络问题

    https://blog.csdn.net/wangmx1993328/article/details/80897533

  6. java执行jar包出错:Unable to access jarfile

    java执行jar包出错:Unable to access jarfile 错误的原因有多种: 1.一般都是路径不正确.在Windows中,正确的路径类似于: java -jar "D:\W ...

  7. SVN集成compare4比较软件

    打开TortoiseSVN的Setting,选择左边的Diff Viewer 设置如下: "D:\Program Files\Beyond Compare 4\BComp.exe" ...

  8. Django的Rbac介绍2

    上一篇博客我们记录了一下Django中使用Rbac,但是上一篇博客中的方法有一点不好,就是,因为我要在html文件中控制:如果用户有某个权限,则显示这个权限所代表的按钮,但是我现在只有1张表的增删改查 ...

  9. EasyUI Dialog 对话框默认不弹出和关闭清空对话框内容

    EasyUI中文网: http://www.jeasyui.net/plugins/181.html 默认不弹出:closed:true 模式化窗口(有遮罩):modal:true <div c ...

  10. cloud server ribbon 自定义策略配置

    虽然ribbon默认为我们提供了多钟负载均衡策略,但有时候我们仍然需要自定义符合自身业务逻辑的规则 使用配置文件的方式:我们只需要在配置文件中添加配置 serviceId.ribbon.NFLoadB ...