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(); } } }
參考:接口
天天用心記錄一點點。內容也許不重要,但習慣很重要!