<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在平時的開發過程中,會有很多場景需要實時監聽檔案的變化,如下:
1、通過實時監控 mysql 的 binlog 紀錄檔實現資料同步
2、修改組態檔後,希望系統可以實時感知
3、應用系統將紀錄檔寫入檔案中,紀錄檔監控系統可以實時抓取紀錄檔,分析紀錄檔內容並進行報警
4、類似 ide 工具,可以實時感知管理的工程下的檔案變更
在 Java 語言中,從 JDK7 開始,新增了java.nio.file.WatchService
類,用來實時監控檔案的變化。
FileWatchedService 類:
package org.learn.file; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardWatchEventKinds; import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; import java.util.List; /** * 實時監控檔案的變化 * * @author zhibo * @date 2019-07-30 20:37 */ public class FileWatchedService { private WatchService watchService; private FileWatchedListener listener; /** * * @param path 要監聽的目錄,注意該 Path 只能是目錄,否則會報錯 java.nio.file.NotDirectoryException: /Users/zhibo/logs/a.log * @param listener 自定義的 listener,用來處理監聽到的建立、修改、刪除事件 * @throws IOException */ public FileWatchedService(Path path, FileWatchedListener listener) throws IOException { watchService = FileSystems.getDefault().newWatchService(); path.register(watchService, /// 監聽檔案建立事件 StandardWatchEventKinds.ENTRY_CREATE, /// 監聽檔案刪除事件 StandardWatchEventKinds.ENTRY_DELETE, /// 監聽檔案修改事件 StandardWatchEventKinds.ENTRY_MODIFY); // // path.register(watchService, // new WatchEvent.Kind[]{ // StandardWatchEventKinds.ENTRY_MODIFY, // StandardWatchEventKinds.ENTRY_CREATE, // StandardWatchEventKinds.ENTRY_DELETE // }, // SensitivityWatchEventModifier.HIGH); this.listener = listener; } private void watch() throws InterruptedException { while (true) { WatchKey watchKey = watchService.take(); List<WatchEvent<?>> watchEventList = watchKey.pollEvents(); for (WatchEvent<?> watchEvent : watchEventList) { WatchEvent.Kind kind = watchEvent.kind(); WatchEvent<Path> curEvent = (WatchEvent<Path>) watchEvent; if (kind == StandardWatchEventKinds.OVERFLOW) { listener.onOverflowed(curEvent); continue; } else if (kind == StandardWatchEventKinds.ENTRY_CREATE) { listener.onCreated(curEvent); continue; } else if (kind == StandardWatchEventKinds.ENTRY_MODIFY) { listener.onModified(curEvent); continue; } else if (kind == StandardWatchEventKinds.ENTRY_DELETE) { listener.onDeleted(curEvent); continue; } } /** * WatchKey 有兩個狀態: * {@link sun.nio.fs.AbstractWatchKey.State.READY ready} 就緒狀態:表示可以監聽事件 * {@link sun.nio.fs.AbstractWatchKey.State.SIGNALLED signalled} 有資訊狀態:表示已經監聽到事件,不可以接續監聽事件 * 每次處理完事件後,必須呼叫 reset 方法重置 watchKey 的狀態為 ready,否則 watchKey 無法繼續監聽事件 */ if (!watchKey.reset()) { break; } } } public static void main(String[] args) { try { Path path = Paths.get("/Users/zhibo/logs/"); FileWatchedService fileWatchedService = new FileWatchedService(path, new FileWatchedAdapter()); fileWatchedService.watch(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }
FileWatchedListener 類:
package org.learn.file; import java.nio.file.Path; import java.nio.file.WatchEvent; public interface FileWatchedListener { void onCreated(WatchEvent<Path> watchEvent); void onDeleted(WatchEvent<Path> watchEvent); void onModified(WatchEvent<Path> watchEvent); void onOverflowed(WatchEvent<Path> watchEvent); }
FileWatchedAdapter 類:
package org.learn.file; import java.nio.file.Path; import java.nio.file.WatchEvent; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; /** * 檔案監聽介面卡 * * @author zhibo * @date 2019-07-31 11:07 */ public class FileWatchedAdapter implements FileWatchedListener { @Override public void onCreated(WatchEvent<Path> watchEvent) { Path fileName = watchEvent.context(); System.out.println(String.format("檔案【%s】被建立,時間:%s", fileName, now())); } @Override public void onDeleted(WatchEvent<Path> watchEvent) { Path fileName = watchEvent.context(); System.out.println(String.format("檔案【%s】被刪除,時間:%s", fileName, now())); } @Override public void onModified(WatchEvent<Path> watchEvent) { Path fileName = watchEvent.context(); System.out.println(String.format("檔案【%s】被修改,時間:%s", fileName, now())); } @Override public void onOverflowed(WatchEvent<Path> watchEvent) { Path fileName = watchEvent.context(); System.out.println(String.format("檔案【%s】被丟棄,時間:%s", fileName, now())); } private String now(){ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); return dateFormat.format(Calendar.getInstance().getTime()); } }
執行以上程式碼,啟動監控任務,然後我在/Users/zhibo/logs/
目錄中建立、修改、刪除檔案,命令如下:
應用程式感知到檔案變化,列印紀錄檔如下:
大家可以看到,監控任務基本上是以 10 秒為單位進行紀錄檔列印的,也就是說修改一個檔案,WatchService 10秒之後才能感知到檔案的變化,沒有想象中的那麼實時。根據以上的經驗,推測可能是 WatchService 做了定時的操作,時間間隔為 10 秒。通過翻閱原始碼發現,在 PollingWatchService
中確實存在一個固定時間間隔的排程器,如下圖:
該排程器的時間間隔有 SensitivityWatchEventModifier
進行控制,該類提供了 3 個級別的時間間隔,分別為2秒、10秒、30秒,預設值為 10秒。SensitivityWatchEventModifier
原始碼如下:
package com.sun.nio.file; import java.nio.file.WatchEvent.Modifier; public enum SensitivityWatchEventModifier implements Modifier { HIGH(2), MEDIUM(10), LOW(30); private final int sensitivity; public int sensitivityValueInSeconds() { return this.sensitivity; } private SensitivityWatchEventModifier(int var3) { this.sensitivity = var3; } }
通過改變時間間隔來進行驗證,將
path.register(watchService, /// 監聽檔案建立事件 StandardWatchEventKinds.ENTRY_CREATE, /// 監聽檔案刪除事件 StandardWatchEventKinds.ENTRY_DELETE, /// 監聽檔案修改事件 StandardWatchEventKinds.ENTRY_MODIFY);
修改為:
path.register(watchService, new WatchEvent.Kind[]{ StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE }, SensitivityWatchEventModifier.HIGH);
檢視紀錄檔,發現正如我們的推斷,WatchService 正以每 2 秒的時間間隔感知檔案變化。
在 stackoverflow 中也有人提出了該問題,問題:Is Java 7 WatchService Slow for Anyone Else,我的 mac 系統中確實存在該問題,由於手頭沒有 windows、linux 系統,因此無法進行這兩個系統的驗證。
到此這篇關於java.nio.file.WatchService 實時監控檔案變化的文章就介紹到這了,更多相關java.nio.file.WatchService 監控檔案變化內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45