NIO不但引進了高效的文件通道,並且新增了更加好用的文件工具家族,包括路徑組工具Paths、路徑工具Path、文件組工具Files。先看路徑組工具Paths,該工具提供了靜態方法get,輸入某個文件的路徑字符串,輸出該文件路徑的路徑對象Path。經過get方法獲取路徑對象的代碼示例以下:html
// 根據指定的文件路徑字符串得到對應的Path對象 Path path = Paths.get(mDirName);
有了Path對象以後,就能調用它的各類實例方法了,常見的幾個方法說明以下:
getParent:獲取當前路徑所在的上級目錄的Path對象。
resolve:拼接文件路徑,在當前路徑的末尾添加指定字符串,並返回新的文件路徑。
startsWith:判斷當前路徑是否以指定字符串開頭。
endsWith:判斷當前路徑是否以指定字符串結尾。
toString:獲取當前路徑對應的名稱字符串。
toFile:獲取當前路徑對應的File對象。
看上去路徑組工具Paths和路徑工具Path平淡無奇,並沒有什麼出衆之處。原來真正方便的是文件組工具Files,它集成了衆多實用的功能技巧,且看下列的各個方法說明:
exists:判斷該路徑是否存在。
isDirectory:判斷該路徑是否爲目錄。
isExecutable:判斷該路徑是否容許執行。
isHidden:判斷該路徑是否隱藏。
isReadable:判斷該路徑是否可讀。
isWritable:判斷該路徑是否可寫。
size:獲取該路徑的文件大小。若是該路徑是文件,則返回文件大小;若是該路徑是目錄,則返回目錄基本信息的大小,而非整個目錄的大小。
createDirectory:若是該路徑是個目錄,就建立新目錄。
createFile:若是該路徑是個文件,就建立新文件。
delete:若是該路徑是文件或者空目錄,就把它刪掉。若是該路徑不存在或者目錄非空,就扔出異常。
deleteIfExists:若是該路徑是文件或者空目錄,就把它刪掉(路徑不存在也不報錯)。但若目錄非空,仍是扔出異常。
copy:把文件從源路徑複製到目標路徑。
move:把文件從源路徑移動到目標路徑。
另外,Java8又給Files工具增長了如下幾個方法,使之具有流式處理的能力:
readAllLines:獲取該文件的全部內容行,返回的是字符串清單。
lines:獲取該文件的全部內容行,返回的是字符串流Stream<String>。
list:獲取該目錄下的全部文件與目錄,但不包括子目錄的下級內容,返回的是路徑流Stream<Path>。
walk:獲取該目錄下的全部文件與目錄,且包括指定深度子目錄的下級內容,返回的是路徑流Stream<Path>。程序員
接下來經過幾個實際案例演示以上文件工具的詳細用法。工具
1、經過Path打開文件通道
以前介紹文件通道的時候,提到有兩種方式能夠建立文件通道,第一種方式能夠調用輸入輸出流的getChannel方法獲取通道對象,第二種方式能夠調用隨機文件工具的getChannel方法獲取通道對象。其實還有第三種方式,就是調用FileChannel工具的open方法,根據傳入的Path對象也能得到通道對象。不加選項參數的open方法,默認獲得只讀的文件通道;若要獲得可寫的文件通道,則需給open方法傳入選項參數StandardOpenOption.WRITE。下面是利用路徑工具建立文件通道的代碼例子:spa
// 經過Path打開文件通道 private static void openChannelFromPath() { try { // 根據指定的文件路徑字符串得到對應的Path對象 Path path = Paths.get(mFileName); // 建立文件通道的第三種方式:經過Path打開文件的只讀通道。open方法不加選項參數的話,默認是隻讀權限 FileChannel readChannel = FileChannel.open(path, StandardOpenOption.READ); readChannel.close(); // 建立文件通道的第三種方式:經過Path打開文件的寫入通道。 // open方法的第二個參數指定了文件以只讀方式仍是以可寫方式打開 FileChannel writeChannel = FileChannel.open(path, StandardOpenOption.WRITE); writeChannel.close(); } catch (Exception e) { e.printStackTrace(); } }
須要注意的是,經過Path打開可寫的文件通道有個問題:要是文件通道指向的文件路徑並不存在,那麼往該通道寫入數據將會扔出異常,而非默認建立新文件。於是獲取可寫的文件通道以前必須添加檢查代碼,即判斷指定路徑是否存在,假若該路徑不存在,則要建立一個新文件。完整的檢查代碼以下所示:htm
// 根據文件路徑獲取Path對象。若是指定路徑的文件不存在,就建立一個新文件。 private static Path getPath(String filename) { Path path = Paths.get(filename); if (!Files.exists(path)) { // 該文件路徑並不存在 try { Files.createFile(path); // 在該路徑建立新文件 } catch (IOException e) { e.printStackTrace(); } } return path; }
但是依稀記得,不論是從輸入輸出流獲取文件通道,仍是從隨機文件工具獲取文件通道,都沒有手工建立新文件的步驟呀。那是由於即便指定路徑的文件不存在,輸出流和隨機文件工具都會自動建立文件,無需程序員去手工建立。所以實際開發中若要建立文件通道,基本採起前兩種方式,不多使用Path工具的第三種方式。對象
2、遍歷指定目錄下(不包含子目錄)的全部文件與目錄
調用Files工具的list方法便可實現指定目錄(不包含子目錄)的遍歷功能,list方法返回的遍歷結果爲字符串流,後續便可經過流式處理作進一步的加工。好比要統計指定目錄下面文件與目錄數量,則先調用list方法得到字符串流對象,再調用count方法就能獲得統計數目。具體的統計代碼示例以下:blog
// 根據指定的文件路徑字符串得到對應的Path對象 Path path = Paths.get(mDirName); try { // 計算該目錄下(不包含子目錄)的全部文件與目錄的總數 long listCount = Files.list(path).count(); System.out.println("listCount="+listCount); } catch (Exception e) { e.printStackTrace(); }
3、遍歷指定目錄下(包含子目錄)的全部文件與目錄
假若要求對指定目錄及其子目錄進行遍歷操做,則可調用Files工具的walk方法,該方法支持設定待遍歷的子目錄深度(從當前目錄往下數的目錄層數)。譬如要統計指定目錄及五層之內子目錄下面文件與目錄數量,則先調用walk方法得到字符串流對象,再調用count方法就能獲得統計數目。此時包含子目錄的統計代碼以下所示:圖片
try { // 根據指定的文件路徑字符串得到對應的Path對象 Path path = Paths.get(mDirName); // 遍歷該目錄以及深度在五以內的子目錄,計算其下全部文件與目錄的總數 long count = Files.walk(path, 5).count(); System.out.println("count="+count); } catch (Exception e) { e.printStackTrace(); }
walk方法與list方法一樣返回的都是流對象,因此流式處理的filter、map、collect等方法通通適用,很是方便對某目錄下的全部實體進行篩選操做。例如打算遍歷指定目錄以及深度在五以內的子目錄,並返回其下全部目錄的路徑名稱清單,利用walk方法實現的篩選代碼是下面這樣的:開發
try { // 根據指定的文件路徑字符串得到對應的Path對象 Path path = Paths.get(mDirName); // 遍歷該目錄以及深度在五以內的子目錄,並返回其下全部目錄的路徑名稱清單 List<String> dirs = Files.walk(path, 5) .filter(Files::isDirectory) // 只挑選目錄 .map(it -> it.toString()) // 獲取目錄的路徑名稱 .collect(Collectors.toList()); // 返回清單格式 System.out.println("dirs="+dirs); } catch (Exception e) { e.printStackTrace(); }
因而可知,流式處理在NIO的文件工具中大放異彩,代碼邏輯結構清晰、代碼行數量也少,實爲文件遍歷的一員福將。
經過walk方法篩選指定目錄下的某種類型文件也很方便,例如想要挑出某目錄下面全部的png圖片文件路徑,則採起walk方法輔以流式處理的實現代碼以下所示:字符串
try { // 根據指定的文件路徑字符串得到對應的Path對象 Path path = Paths.get(mDirName); // 遍歷該目錄以及深度在五以內的子目錄,並返回其下全部png文件的路徑名稱清單 List<String> pngs = Files.walk(path, 5) .filter(it -> it.toFile().isFile()) // 只挑選文件 .filter(it -> it.endsWith(".png")) // 挑出擴展名爲png的文件 .map(it -> it.toString()) // 獲取目錄的路徑名稱 .collect(Collectors.toList()); // 返回清單格式 System.out.println("pngs="+pngs); } catch (Exception e) { e.printStackTrace(); }
以上的文件篩選代碼果真清爽,一點都不拖泥帶水。
更多Java技術文章參見《Java開發筆記(序)章節目錄》