Java文件樹
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
實例-2
以下代碼顯示如何使用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