小师妹学JavaIO之:文件系统和WatchService
文章目錄
- 簡介
- 監控的痛點
- WatchService和文件系統
- WatchSerice的使用和實現本質
- 總結
簡介
小師妹這次遇到了監控文件變化的問題,F師兄給小師妹介紹了JDK7 nio中引入的WatchService,沒想到又順道普及了一下文件系統的概念,萬萬沒想到。
監控的痛點
小師妹:F師兄最近你有沒有感覺到呼吸有點困難,后領有點涼颼颼的,說話有點不順暢的那種?
沒有啊小師妹,你是不是秋衣穿反了?
小師妹:不是的F師兄,我講的是心里的感覺,那種莫須有的壓力,還有一絲悸動纏繞在心。
別繞彎子了小師妹,是不是又遇到問題了。
更多精彩內容且看:
- 區塊鏈從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特幣等持續更新
- Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
- Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
- java程序員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程
更多內容請訪問www.flydean.com
小師妹:還是F師兄懂我,這不上次的Properties文件用得非常上手,每次修改Properties文件都要重啟java應用程序,真的是很痛苦。有沒有什么其他的辦法呢?
辦法當然有,最基礎的辦法就是開一個線程定時去監控屬性文件的最后修改時間,如果修改了就重新加載,這樣不就行了。
小師妹:寫線程啊,這么麻煩,有沒有什么更簡單的辦法呢?
就知道你要這樣問,還好我準備的比較充分,今天給你介紹一個JDK7在nio中引入的類WatchService。
WatchService和文件系統
WatchService是JDK7在nio中引入的接口:
監控的服務叫做WatchService,被監控的對象叫做Watchable:
WatchKey register(WatchService watcher,WatchEvent.Kind<?>[] events,WatchEvent.Modifier... modifiers)throws IOException; WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events)throws IOException;Watchable通過register將該對象的WatchEvent注冊到WatchService上。從此只要有WatchEvent發生在Watchable對象上,就會通知WatchService。
WatchEvent有四種類型:
register返回的WatchKey就是監聽到的WatchEvent的集合。
現在來看WatchService的4個方法:
小師妹:F師兄,那怎么才能構建一個WatchService呢?
上次文章中說的文件系統,小師妹還記得吧,FileSystem中就有一個獲取WatchService的方法:
public abstract WatchService newWatchService() throws IOException;我們看下FileSystem的結構圖:
在我的mac系統上,FileSystem可以分為三大類,UnixFileSystem,JrtFileSystem和ZipFileSystem。我猜在windows上面應該還有對應的windows相關的文件系統。小師妹你要是有興趣可以去看一下。
小師妹:UnixFileSystem用來處理Unix下面的文件,ZipFileSystem用來處理zip文件。那JrtFileSystem是用來做什么的?
哎呀,這就又要扯遠了,為什么每次問問題都要扯到天邊…
從前當JDK還是9的時候,做了一個非常大的改動叫做模塊化JPMS(Java Platform Module System),這個Jrt就是為了給模塊化系統用的,我們來舉個例子:
public void useJRTFileSystem(){String resource = "java/lang/Object.class";URL url = ClassLoader.getSystemResource(resource);log.info("{}",url);}上面一段代碼我們獲取到了Object這個class的url,我們看下如果是在JDK8中,輸出是什么:
jar:file:/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/rt.jar!/java/lang/Object.class輸出結果是jar:file表示這個Object class是放在jar文件中的,后面是jar文件的路徑。
如果是在JDK9之后:
jrt:/java.base/java/lang/Object.class結果是jrt開頭的,java.base是模塊的名字,后面是Object的路徑。看起來是不是比傳統的jar路徑更加簡潔明了。
有了文件系統,我們就可以在獲取系統默認的文件系統的同時,獲取到相應的WatchService:
WatchService watchService = FileSystems.getDefault().newWatchService();WatchSerice的使用和實現本質
小師妹:F師兄,WatchSerice是咋實現的呀?這么神奇,為我們省了這么多工作。
其實JDK提供了這么多類的目的就是為了不讓我們重復造輪子,之前跟你講監控文件的最簡單辦法就是開一個獨立的線程來監控文件變化嗎?其實…WatchService就是這樣做的!
PollingWatchService() {// TBD: Make the number of threads configurablescheduledExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {@Overridepublic Thread newThread(Runnable r) {Thread t = new Thread(null, r, "FileSystemWatcher", 0, false);t.setDaemon(true);return t;}});}上面的方法就是生成WatchService的方法,小師妹看到沒有,它的本質就是開啟了一個daemon的線程,用來接收監控任務。
下面看下怎么把一個文件注冊到WatchService上面:
private void startWatcher(String dirPath, String file) throws IOException {WatchService watchService = FileSystems.getDefault().newWatchService();Path path = Paths.get(dirPath);path.register(watchService, ENTRY_MODIFY);Runtime.getRuntime().addShutdownHook(new Thread(() -> {try {watchService.close();} catch (IOException e) {log.error(e.getMessage());}}));WatchKey key = null;while (true) {try {key = watchService.take();for (WatchEvent<?> event : key.pollEvents()) {if (event.context().toString().equals(fileName)) {loadConfig(dirPath + file);}}boolean reset = key.reset();if (!reset) {log.info("該文件無法重置");break;}} catch (Exception e) {log.error(e.getMessage());}}}上面的關鍵方法就是path.register,其中Path是一個Watchable對象。
然后使用watchService.take來獲取生成的WatchEvent,最后根據WatchEvent來處理文件。
總結
道生一,一生二,二生三,三生萬物。一個簡簡單單的功能其實背后隱藏著…道德經,哦,不對,背后隱藏著道的哲學。
本文的例子https://github.com/ddean2009/learn-java-io-nio
本文作者:flydean程序那些事
本文鏈接:http://www.flydean.com/java-io-file-watchservice/
本文來源:flydean的博客
歡迎關注我的公眾號:程序那些事,更多精彩等著您!
總結
以上是生活随笔為你收集整理的小师妹学JavaIO之:文件系统和WatchService的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小师妹学JavaIO之:目录还是文件
- 下一篇: 小师妹学JavaIO之:文件File和路