天天看點

小師妹學JavaIO之:目錄還是檔案

文章目錄

  • 簡介
  • linux中的檔案和目錄
  • 目錄的基本操作
  • 目錄的進階操作
  • 目錄的腰疼操作
  • 總結

目錄和檔案傻傻分不清楚,目錄和檔案的本質到底是什麼?在java中怎麼操縱目錄,怎麼周遊目錄。本文F師兄會為大家一一講述。

小師妹:F師兄,我最近有一個疑惑,java代碼中好像隻有檔案沒有目錄呀,是不是當初發明java的大神,一不小心走了神?

F師兄:小師妹真勇氣可嘉呀,敢于質疑權威是從小工到專家的最重要的一步。想想F師兄我,從小沒人提點,老師講什麼我就信什麼,專家說什麼我就聽什麼:股市必上一萬點,房子是給人住的不是給人炒的,原油寶當然是小白理财必備産品…然後,就沒有然後了。

更多精彩内容且看:

  • 區塊鍊從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特币等持續更新
  • Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
  • Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
  • java程式員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程
更多内容請通路www.flydean.com

雖然java中沒有目錄的概念隻有File檔案,而File其實是可以表示目錄的:

public boolean isDirectory()      

File中有個isDirectory方法,可以判斷該File是否是目錄。

File和目錄傻傻分不清楚,小師妹,有沒有聯想到點什麼?

小師妹:F師兄,我記得你上次講到Linux下面所有的資源都可以看做是檔案,在linux下面檔案和目錄的本質是不是一樣的?

對的,在linux下面檔案是一等公民,所有的資源都是以檔案的形式來區分的。

什麼扇區,邏輯塊,頁之類的底層結構我們就不講了。我們先考慮一下一個檔案到底應該包含哪些内容。除了檔案本身的資料之外,還有很多中繼資料的東西,比如檔案權限,所有者,group,建立時間等資訊。

在linux系統中,這兩個部分是分開存儲的。存放資料本身的叫做block,存放中繼資料的叫做inode。

inode中存儲了block的位址,可以通過inode找到檔案實際資料存儲的block位址,進而進行檔案通路。考慮一下大檔案可能占用很多個block,是以一個inode中可以存儲多個block的位址,而一個檔案通常來說使用一個inode就夠了。

小師妹學JavaIO之:目錄還是檔案

為了顯示層級關系和友善檔案的管理,目錄的資料檔案中存放的是該目錄下的檔案和檔案的inode位址,進而形成了一種一環套一環,圓環套圓環的鍊式關系。

小師妹學JavaIO之:目錄還是檔案

上圖列出了一個通過目錄查找其下檔案的環中環布局。

我想java中目錄沒有單獨列出來一個類的原因可能是參考了linux底層的檔案布局吧。

因為在java中目錄和檔案是公用File這個類的,是以File的基本操作目錄它全都會。

基本上,目錄和檔案相比要多注意下面三類方法:

public boolean isDirectory()public File[] listFiles() public boolean mkdir()      

為什麼說是三類呢?因為還有幾個和他們比較接近的方法,這裡就不一一列舉了。

isDirectory判斷該檔案是不是目錄。listFiles列出該目錄下面的所有檔案。mkdir建立一個檔案目錄。

小師妹:F師兄,之前我們還以目錄的周遊要耗費比較長的時間,經過你一講解目錄的資料結構,感覺listFiles并不是一個耗時操作呀,所有的資料都已經準備好了,直接讀取出來就行。

對,看問題不要看表面,要看到隐藏在表面的本質内涵。你看師兄我平時不顯山露水,其實是真正的中流砥柱,堪稱公司優秀員工模範。

小師妹:F師兄,那平時也沒看上頭表彰你啥的?哦,我懂了,一定是老闆怕表彰了你引起别人的嫉妒,會讓你的好好大師兄的形象崩塌吧,看來老闆真的懂你呀。

好了小師妹,你懂了就行,下面F師兄給你講一下目錄的進階操作,比如我們怎麼拷貝一個目錄呀?

小師妹,拷貝目錄簡單的F師兄,上次你就教我了:

cp -rf      

一個指令的事情不就解決了嗎?難道裡面還隐藏了點秘密?

咳咳咳,秘密倒是沒有,小師妹,我記得你上次說要對java從一而終的,今天師兄給你介紹一個在java中拷貝檔案目錄的方法。

其實Files工具類裡已經為我們提供了一個拷貝檔案的優秀方法:

public static Path copy(Path source, Path target, CopyOption... options)      

使用這個方法,我們就可以進行檔案的拷貝了。

如果想要拷貝目錄,就周遊目錄中的檔案,循環調用這個copy方法就夠了。

小師妹:且慢,F師兄,如果目錄下面還有目錄的,目錄下還套目錄的情況該怎麼處理?

這就是圈套呀,看我用個遞歸的方法解決它:

public void useCopyFolder() throws IOException {File sourceFolder = new File("src/main/resources/flydean-source");File destinationFolder = new File("src/main/resources/flydean-dest");copyFolder(sourceFolder, destinationFolder);}private static void copyFolder(File sourceFolder, File destinationFolder) throws IOException{//如果是dir則遞歸周遊建立dir,如果是檔案則直接拷貝if (sourceFolder.isDirectory()){//檢視目标dir是否存在if (!destinationFolder.exists()){destinationFolder.mkdir();log.info("目标dir已經建立: {}",destinationFolder);}for (String file : sourceFolder.list()){File srcFile = new File(sourceFolder, file);File destFile = new File(destinationFolder, file);copyFolder(srcFile, destFile);}}else{//使用Files.copy來拷貝具體的檔案Files.copy(sourceFolder.toPath(), destinationFolder.toPath(), StandardCopyOption.REPLACE_EXISTING);log.info("拷貝目标檔案: {}",destinationFolder);}}      

基本思想就是遇到目錄我就周遊,遇到檔案我就拷貝。

小師妹:F師兄,假如我想删除一個目錄中的檔案,或者我們想統計一下這個目錄下面到底有多少個檔案該怎麼做呢?

雖然這些操作有點腰疼,還是可以解決的,Files工具類中有個方法叫做walk,傳回一個Stream對象,我們可以使用Stream的API來對檔案進行處理。

删除檔案:

public void useFileWalkToDelete() throws IOException {Path dir = Paths.get("src/main/resources/flydean");Files.walk(dir).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);}      

統計檔案:

 public void useFileWalkToSumSize() throws IOException {Path folder = Paths.get("src/test/resources");long size = Files.walk(folder).filter(p -> p.toFile().isFile()).mapToLong(p -> p.toFile().length()).sum();log.info("dir size is: {}",size);}