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