在讀2.2節關於路徑的內容時,你可能已經猜到目錄不過是帶有特別屬性的Path
。遍歷目錄的能力是Java 7引人注目的新特性。新加入的java.nio.file.DirectoryStream<T>
接口和它的實現類提供了很多功能:
- 循環遍歷目錄中的子項,比如查找目錄中的文件;
- 用glob表達式1(比如
*Foobar*
)進行目錄子項匹配和基於MIME的內容檢測(比如text/xml
文件); - 用
walkFileTree
方法實現遞歸移動、複製和刪除操作。
本節主要討論兩個常見用例:在一個目錄中查找文件以及在目錄樹中執行相同的任務。我們先從最簡單的開始:在一個目錄中查找任意文件。
1 glob通常指有限的模式匹配,源自早期Unix中的glob庫函數,該函數用於查找文件系統中指定模式的路徑,雖然所用語法和正則表達式類似,但沒有正則表達式那麼強大的表達力,詳見附錄B。——譯者注
2.3.1 在目錄中查找文件
我們先討論一個簡單的例子,用模式匹配過濾出java7developer項目中所有的.properties文件。請看下面的代碼:
代碼清單2-2 列出目錄下的properties文件
Path dir = Paths.get(\"C:\\workspace\\java7developer\");//1設定起始路徑
try(DirectoryStream<Path> stream
= Files.newDirectoryStream(dir, \"*.properties\")){//2聲明過濾流
//3 找出所有.properties 文件並輸出
for (Path entry: stream)
{
System.out.println(entry.getFileName);
}
}
catch (IOException e)
{
System.out.println(e.getMessage);
}
最前面是我們已經熟悉的Paths.get(String)
調用1。緊隨其後的是關鍵方法DirectoryStream(Path directory, String patternMatch)
2,它返回一個經過過濾的DirectoryStream
,其中包含以.properties結尾的文件。最後輸出每個子項3。
過濾流中用到的模式匹配稱為glob模式匹配,它和Perl正則表達式類似,但稍有不同。附錄B中有如何使用glob模式匹配的詳細說明。
代碼清單2-2展示了新API處理單個目錄的能力,但如果需要遞歸過濾多個目錄時該怎麼辦?
2.3.2 遍歷目錄樹
Java 7支持整個目錄樹的遍歷。也就是說你可以很容易地搜尋目錄樹中的文件,在子目錄中查找,並對它們執行操作。比如你可能想在做開發的機器上弄個工具類來刪除目錄/opt/workspace/java下的所有.class文件,完成構建前的清除工作。
遍歷目錄樹是Java 7的新特性,要想正確使用,你得掌握一些接口及其實現的細節。其中的關鍵方法是:
Files.walkFileTree(Path startingDir, FileVisitor<? superPath> visitor);
提供startingDir
非常簡單,但給出FileVisitor
接口的實現類就比較麻煩了(參數FileVisitor<? superPath> visitor
看上去就不是善茬兒),因為最少得實現下面5個方法(T
一般就是Path
):
FileVisitResult preVisitDirectory(T dir)
FileVisitResult preVisitDirectoryFailed(T dir, IOException exc)
FileVisitResult visitFile(T file, BasicFileAttributes attrs)
FileVisitResult visitFileFailed(T file, IOException exc)
FileVisitResult postVisitDirectory(T dir, IOException exc)
看起來挺嚇人的吧?好在Java 7 API的設計者們已經提供了一個默認實現類,SimpleFileVisitor<T>
。
我們要擴展並修改代碼清單2-2。下面的代碼會列出C:workspacejava7developersrc目錄下及其子目錄內的所有.java文件。這段代碼展示了Files.walkFileTree
方法對默認實現類SimpleFileVisitor
的用法,用一個特定的visitFile
方法實現來改進它。
代碼清單2-3 列出子目錄下的所有java源碼文件
public class Find
{
public static void main(String args) throws IOException
{
Path startingDir =
Paths.get(\"C:\\workspace\\java7developer\\src\");//設置起始目錄
Files.walkFileTree(startingDir,
new FindJavaVisitor); //1調用walkFileTree
}
private static class FindJavaVisitor
extends SimpleFileVisitor<Path> //2擴展SimpleFileVisitor<Path>
{
@Override
public FileVisitResult
visitFile(Path file, BasicFileAttributes attrs) //3 重寫visitFile方法
{
if (file.toString.endsWith(\".java\")) {
System.out.println(file.getFileName);
}
return FileVisitResult.CONTINUE;
}
}
}
整個過程從調用Files.walkFileTree
方法開始1。這裡的關鍵是 FindJavaVisitor
,該類擴展了FileVisitor
的默認實現類SimpleFileVisitor
2。你想讓SimpleFileVisitor
來完成大部分工作,比如遍歷目錄。可實際上你唯一要做的就是重寫visitFile(Path,BasicFileAttributes)
1方法3,在這個方法中你也只需要寫些代碼來判斷文件名是否以.java結尾,如果確實是,就在stdout中輸出。
1 2.4節會介紹BasicFileAttributes
,所以暫時不用管它。
其他用例包括遞歸移動、複製、刪除或者修改文件。在大多數應用場景中,你只需要擴展SimpleFileVisitor
。但如果你想實現自己的FileVisitor
,API也很靈活。
注意 為了確保遞歸等操作的安全性,
walkFileTree
方法不會自動跟隨符號鏈接。如果你確實需要跟隨符號鏈接,就需要檢查那個屬性(如2.4.3節所述)並執行相應的操作。
現在你對路徑和目錄樹已經熟悉了,該從處理位置進入真正的文件系統操作上了,接下來我們會向你介紹新的Files
類及它的朋友們。