FileVisitor
API可以遞回地處理檔案樹中的所有檔案和目錄。當要對檔案樹中的所有或某些檔案或目錄執行某些操作時,FileVisitor
API非常有用。
SimpleFileVisitor
類是FileVisitor
介面的基本實現。當存取檔案/目錄時,SimpleFileVisitor
類不執行任何操作。可以從SimpleFileVisitor
類繼承檔案存取-FileVisitor
類,並且只覆蓋需要的方法。
FileVisitor
介面的方法
編號 | 含義 |
---|---|
1 | FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) 在存取目錄中的條目之前呼叫一次。 |
2 | FileVisitResult postVisitDirectory(T dir,IOException exc) 已存取目錄中的後呼叫項。如果在目錄的疊代期間丟擲了任何異常,則將異常物件作為第二個引數傳遞給此方法。如果此方法的第二個引數為null ,則在目錄疊代期間沒有異常。 |
3 | FileVisitResult visitFile(T file, BasicFileAttributes attrs) 是在當存取目錄中的檔案時呼叫。 |
4 | FileVisitResult visitFileFailed(T file, IOException exc) 是當由於任何原因而無法存取檔案或目錄時呼叫。 |
下表列出了FileVisitResult
的列舉常數及其說明 -
列舉常數 | 描述/含義 |
---|---|
CONTINUE | 繼續處理 |
SKIP_SIBLINGS | 繼續處理而不存取檔案或目錄的同級。 |
SKIP_SUBTREE | 繼續處理,而不存取目錄中的條目。 |
TERMINATE | 終止檔案存取過程。 |
不需要在檔案存取類的所有四個方法中編寫邏輯。要複製目錄,請使用preVisitDirectory()
方法來建立一個新目錄,並使用visitFile()
方法來複製該檔案。
以下程式碼顯示如何列印目錄的子目錄和檔案的名稱。
import static java.nio.file.FileVisitResult.CONTINUE;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
public class Main {
public static void main(String[] args) {
Path startDir = Paths.get("");
FileVisitor<Path> visitor = getFileVisitor();
try {
Files.walkFileTree(startDir, visitor);
} catch (IOException e) {
e.printStackTrace();
}
}
public static FileVisitor<Path> getFileVisitor() {
class DirVisitor<Path> extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
System.out.format("%s [Directory]%n", dir);
return CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
System.out.format("%s [File, Size: %s bytes]%n", file, attrs.size());
return CONTINUE;
}
}
FileVisitor<Path> visitor = new DirVisitor<>();
return visitor;
}
}
上面的程式碼生成以下結果。
[Directory]
.classpath [File, Size: 232 bytes]
.project [File, Size: 382 bytes]
.settings [Directory]
.settings\org.eclipse.core.resources.prefs [File, Size: 57 bytes]
bin [Directory]
bin\Main$1DirVisitor.class [File, Size: 1648 bytes]
bin\Main.class [File, Size: 1338 bytes]
destfile.txt [File, Size: 25 bytes]
luci3.txt [File, Size: 25 bytes]
my_second_file.txt [File, Size: 0 bytes]
person.ser [File, Size: 160 bytes]
personext.ser [File, Size: 93 bytes]
primitives.dat [File, Size: 42 bytes]
randomaccessfile.txt [File, Size: 18 bytes]
src [Directory]
src\Calculator.java [File, Size: 0 bytes]
src\Main.class [File, Size: 1111 bytes]
src\Main.java [File, Size: 1172 bytes]
stdout.txt [File, Size: 34 bytes]
test.txt [File, Size: 13 bytes]
ziptest.zip [File, Size: 22 bytes]
以下程式碼顯示如何使用FileVisitor
API刪除目錄樹,把目錄 C:\Java_Dev
和其中的所有內容刪除。
import static java.nio.file.FileVisitResult.CONTINUE;
import static java.nio.file.FileVisitResult.TERMINATE;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
public class Main {
public static void main(String[] args) {
Path dirToDelete = Paths.get("C:\\Java_Dev");
FileVisitor<Path> visitor = getFileVisitor();
try {
Files.walkFileTree(dirToDelete, visitor);
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
public static FileVisitor<Path> getFileVisitor() {
class DeleteDirVisitor extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {
FileVisitResult result = CONTINUE;
if (e != null) {
System.out.format("Error deleting %s. %s%n", dir, e.getMessage());
result = TERMINATE;
} else {
Files.delete(dir);
System.out.format("Deleted directory %s%n", dir);
}
return result;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
System.out.format("Deleted file %s%n", file);
return CONTINUE;
}
}
FileVisitor<Path> visitor = new DeleteDirVisitor();
return visitor;
}
}
上面的程式碼生成以下結果。
Deleted file C:\Java_Dev\dir1\test1.txt
Deleted directory C:\Java_Dev\dir1
Deleted directory C:\Java_Dev\dir1 - 副本
Deleted file C:\Java_Dev\dir2\test1.txt
Deleted directory C:\Java_Dev\dir2
Deleted file C:\Java_Dev\test1.txt
Deleted file C:\Java_Dev\twinkle.txt
Deleted directory C:\Java_Dev
以下程式碼顯示如何使用walkFileTree()
方法跟隨符號連結。
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.EnumSet;
import java.util.Set;
import static java.nio.file.FileVisitOption.FOLLOW_LINKS;
public class Main {
public static void main(String[] args) throws Exception {
Path startDir = Paths.get("");
FileVisitor<Path> visitor = create your visitor;
Set<FileVisitOption> options = EnumSet.of(FOLLOW_LINKS);
int depth = Integer.MAX_VALUE;
Files.walkFileTree(startDir, options, depth, visitor);
}
}
可以使用glob
和正規表示式模式對字串形式的Path
物件執行模式匹配。
功能介面PathMatcher
用於執行匹配。它包含一個matches(Path path)
方法,如果指定的路徑匹配模式,則該方法返回true
。
模式字串由兩部分組成,語法和模式由冒號分隔:
syntax:pattern
語法的值是glob
或regex
。模式部分遵循取決於語法部分的值。glob
模式使用以下語法規則:
*
匹配零個或多個字元,而不會交叉目錄邊界。**
匹配零個或多個字元跨目錄邊界。?
只匹配一個字元。\
跳脫以下字元的特殊含義。\\
匹配單個反斜槓\*
匹配一個星號。放在括號[]
中的字元稱為括號表示式,它匹配單個字元。如:[aeiou]
將匹配a
,e
,i
,o
或u
。
兩個字元之間的破折號指定範圍。[a-z]
匹配a
和z
之間的所有字母。左括號後的感嘆號(!
)被視為否定。 [!abc]
匹配除了a
,b
和c
之外的所有字元。
通過在大括號({}
)中指定逗號分隔的子模式來使用一組子模式。 例如,{txt,java,doc}
匹配txt
,java
和doc
。
路徑的根元件的匹配是實現相關的。以下程式碼顯示了如何使用PathMatcher
物件將路徑與glob
模式匹配。
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
public class Main {
public static void main(String[] args) {
String globPattern = "glob:**txt";
PathMatcher matcher = FileSystems.getDefault().getPathMatcher(globPattern);
Path path = Paths.get("C:\\Java_Dev\\test1.txt");
boolean matched = matcher.matches(path);
System.out.format("%s matches %s: %b%n", globPattern, path, matched);
}
}
執行上面的程式碼,得到以下結果 -
glob:**txt matches C:\Java_Dev\test1.txt: true