JDK 规范目录(http://www.javashuo.com/article/p-wdnembkc-ex.html)html
具体详见:https://blog.csdn.net/lirx_tech/article/details/51425364java
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) AbstractWatchServiceide
// 等待要处理的事件 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 中塞数据。this
final void enqueueKey(WatchKey key) { pendingKeys.offer(key); }
(2) WindowsWatchService.net
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 的内部类,开启了一个线程监控目录。code
(3) Pollerhtm
重点关注 Poller 中的 run 方法。blog
@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(); } } }
参考:接口
天天用心记录一点点。内容也许不重要,但习惯很重要!