原文鏈接:
http://www.jetbrains.org/intellij/sdk/docs/basics/virtual_file_system.html
虛擬文件系統(tǒng)(VFS)是IntelliJ平臺(tái) 的一個(gè)組件蕾域,它封裝了處理文件的大部分操作算利。它主要有以下幾個(gè)目的:
- 提供一個(gè)處理文件的通用API诗越,而不用管文件的真實(shí)位置(磁盤上、歸檔中或HTTP服務(wù)器上);
- 跟蹤文件修改,并在檢測(cè)到修改時(shí)提供文件內(nèi)容的舊版本和新版本;
- 提供將其它持久性數(shù)據(jù)與VFS中的文件關(guān)聯(lián)的可能性见秤。
為了提供后兩個(gè)特性砂竖,VFS管理用戶硬盤的某些內(nèi)容的持久性快照。 快照僅存儲(chǔ)那些至少被VFS API請(qǐng)求一次的文件鹃答,并且異步更新匹配磁盤上發(fā)生的更改乎澄。
快照是應(yīng)用級(jí),而不是項(xiàng)目級(jí)的测摔。因此置济,即使多個(gè)項(xiàng)目引用了某些文件(例如,JDK中的類)避咆,VFS也只會(huì)存儲(chǔ)一個(gè)副本舟肉。
所有VFS的訪問操作都通過快照。
如果通過VFS API請(qǐng)求的某些信息的快照不可用查库,則將從磁盤加載它并將其存儲(chǔ)到快照中。 如果信息在快照中可用黄琼,則返回快照數(shù)據(jù)樊销。 只有訪問了特定信息,目錄中的文件內(nèi)容和文件列表才會(huì)存儲(chǔ)在快照中 - 否則只會(huì)存儲(chǔ)名稱脏款,長(zhǎng)度围苫,時(shí)間戳等屬性的文件元數(shù)據(jù)。
注意 這意味著文件系統(tǒng)的狀態(tài)和IntelliJ Platform UI中顯示的來自快照的文件內(nèi)容并不總是匹配磁盤的實(shí)際內(nèi)容撤师。
例如在某些情況下剂府,IntelliJ平臺(tái)外部刪除的文件在UI中仍然可以顯示一段時(shí)間。
快照在刷新操作 期間從磁盤更新剃盾,這通常是異步的腺占。 所有通過VFS進(jìn)行的寫操作都是同步的——即內(nèi)容立即保存到磁盤。
刷新操作使VFS的一部分狀態(tài)與實(shí)際磁盤的內(nèi)容同步痒谴。 刷新操作由* IntelliJ平臺(tái) *或插件代碼顯式調(diào)用衰伯,即當(dāng)IDE運(yùn)行時(shí)在磁盤上的文件更改時(shí),VFS不會(huì)立即更新积蔚。 VFS將在下一次刷新操作后更新文件意鲸。
IntelliJ平臺(tái) 會(huì)在啟動(dòng)時(shí)異步刷新整個(gè)項(xiàng)目?jī)?nèi)容。默認(rèn)情況下尽爆,用戶從其它應(yīng)用切換到IDE時(shí)會(huì)執(zhí)行刷新操作怎顾,但是用戶可以通過設(shè)置|外觀和行為|系統(tǒng)設(shè)置|框架或選項(xiàng)卡激活時(shí)同步文件關(guān)閉它
在Windows,Mac和Linux系統(tǒng)中漱贱,IntelliJ平臺(tái) 會(huì)啟動(dòng)一個(gè)本地文件監(jiān)控進(jìn)程接受文件系統(tǒng)的更改通知槐雾。如果文件監(jiān)控可用,刷新操作將只更新更改的文件饱亿,否則將遍歷所有文件夾中文件蚜退。
刷新操作基于文件時(shí)間戳闰靴。 如果文件的內(nèi)容已更改,但其時(shí)間戳保持不變钻注,* IntelliJ平臺(tái) *不會(huì)接收更新的內(nèi)容蚂且。
目前沒有從快照中刪除文件的功能。 如果文件被加載一次幅恋,它將永遠(yuǎn)保留在那里杏死,除非它從磁盤中刪除,并且在其一個(gè)父目錄上調(diào)用了刷新操作捆交。
VFS本身不支持忽略設(shè)置|文件類型|文件中列出的文件和排除項(xiàng)目結(jié)構(gòu)|模塊|源代碼|排除中的文件夾淑翼。 如果應(yīng)用代碼訪問它們,VFS將加載并返回其內(nèi)容品追。 在大多數(shù)情況下玄括,忽略的文件和排除的文件夾必須從較高級(jí)別代碼的處理中跳過。
在IntelliJ平臺(tái)IDE的運(yùn)行實(shí)例的生命周期中肉瓦,多個(gè)VirtualFile
實(shí)例可能對(duì)應(yīng)于同一個(gè)磁盤文件遭京。 它們是相等的,有相同的hashCode
并且共享用戶數(shù)據(jù)泞莉。
同步和異步刷新
從調(diào)用者的角度來看哪雕,刷新操作可以是同步或異步的。 實(shí)際上鲫趁,刷新操作根據(jù)它們自己的線程策略來執(zhí)行斯嚎,同步意味著調(diào)用線程將被阻塞,直到刷新操作(其很可能在不同的線程上運(yùn)行)完成挨厚。
同步和異步刷新都可以從任何線程啟動(dòng)堡僻。 如果從后臺(tái)線程啟動(dòng)刷新,則調(diào)用線程必須不能保持讀取操作幽崩,否則會(huì)發(fā)生死鎖苦始。更多線程模型和讀寫操作的信息請(qǐng)查閱通用線程規(guī)則。
相同的線程要求也適用于像LocalFileSystem.refreshAndFindFileByPath()這樣的函數(shù)慌申,如果在快照中找不到指定路徑的文件陌选,則執(zhí)行部分刷新。
幾乎所有情況下都強(qiáng)烈建議使用異步刷新蹄溉。 如果有一些代碼需要在刷新完成后執(zhí)行咨油,代碼應(yīng)該作為postRunnable
參數(shù)傳遞給以下刷新方法:
在某些情況下,同步刷新可能會(huì)導(dǎo)致死鎖柒爵,具體取決于調(diào)用刷新操作的線程有哪些鎖役电。
虛擬文件系統(tǒng)事件
虛擬文件系統(tǒng)中發(fā)生的所有更改(由于刷新操作或由用戶操作引起)都為虛擬文件系統(tǒng)事件。 VFS事件總是在事件分派線程和寫入操作中觸發(fā)棉胀。
監(jiān)聽VFS事件的最有效的方法是實(shí)現(xiàn)BulkFileListener
接口并訂閱它到VirtualFileManager法瑟。
這個(gè)API使你可以檢測(cè)到在刷新操作期間一個(gè)列表中的所有更改冀膝,并且可以批量處理它們。 你也可以實(shí)現(xiàn)VirtualFileListener接口并使用VirtualFileManager.addVirtualFileListener()注冊(cè)它霎挟,這將允許您逐個(gè)處理事件窝剖。
注意:VFS監(jiān)聽器是應(yīng)用級(jí)的,它會(huì)將接收所有用戶打開項(xiàng)目中發(fā)生的更改事件酥夭。 你可能需要過濾掉與你的任務(wù)無關(guān)的事件赐纱。
VFS事件會(huì)在每次更改前后發(fā)送,你可以在before事件之前訪問文件的舊內(nèi)容熬北。注意疙描,刷新引起的事件會(huì)在磁盤內(nèi)容更改之后發(fā)送——因此,當(dāng)你處理beforeFileDeletion
事件時(shí)讶隐,例如該文件已從磁盤中刪除起胰。 但是,它仍然存在于VFS快照中巫延,你可以使用VFS API訪問其最后的內(nèi)容待错。
注意:請(qǐng)注意,刷新操作僅針對(duì)已加載進(jìn)快照中文件更改觸發(fā)事件烈评。 例如,如果你訪問一個(gè)
VirtualFile
的目錄犯建,但從未使用VirtualFile.getChildren()加載其內(nèi)容讲冠,當(dāng)在該目錄中創(chuàng)建文件時(shí),可能不會(huì)收到fileCreated
通知适瓦。
如果使用VirtualFile.findChild()
加載目錄中的一個(gè)文件竿开,你將收到該文件的更改通知,但是你可能無法收到同一目錄中其它文件的創(chuàng)建/刪除通知玻熙。