import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class DirectoryWalker {
private final List<String> filePaths = new ArrayList<>();
/** 公開入口 */
public List<String> listAll(String rootPath) {
filePaths.clear();
File root = new File(rootPath);
if (root.exists() && root.isDirectory()) {
walk(root);
}
return filePaths;
}
/** 遞歸核心 */
private void walk(File dir) {
File[] children = dir.listFiles();
if (children == null) return; // 權限不足或 IO 錯誤
for (File child : children) {
if (child.isDirectory()) {
walk(child); // 遞歸進入子目錄
} else {
filePaths.add(child.getAbsolutePath()); // 收集檔案
}
}
}
}
public static void main(String[] args) {
DirectoryWalker walker = new DirectoryWalker();
List<String> files = walker.listAll("E:/Struts2");
System.out.println("共發現 " + files.size() + " 個檔案:");
files.forEach(System.out::println);
}
import java.nio.file.*;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
public class ModernWalker {
/** 獲取所有檔案路徑 (含子目錄) */
public static List<String> walkAll(String root) throws IOException {
try (Stream<Path> stream = Files.walk(Paths.get(root))) {
return stream
.filter(Files::isRegularFile) // 僅檔案
.map(Path::toAbsolutePath)
.map(Path::toString)
.collect(Collectors.toList());
}
}
/** 限制最大深度 */
public static List<String> walkDepth(String root, int maxDepth) throws IOException {
try (Stream<Path> stream = Files.walk(Paths.get(root), maxDepth)) {
return stream.filter(Files::isRegularFile)
.map(Path::toString).collect(Collectors.toList());
}
}
/** 串流處理海量檔案 (不累積 List,避免 OOM) */
public static void processAll(String root, Consumer<Path> processor) throws IOException {
try (Stream<Path> stream = Files.walk(Paths.get(root))) {
stream.filter(Files::isRegularFile).forEach(processor);
}
}
}
// 只取 .java 檔且大小 > 1KB
Files.walk(Paths.get(dir))
.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".java"))
.filter(p -> {
try { return Files.size(p) > 1024; }
catch (IOException e) { return false; }
})
.forEach(System.out::println);
// 取特定目錄下所有 .log 檔 (不遞歸)
Files.list(Paths.get(dir)) // 非遞歸
.filter(p -> p.toString().endsWith(".log"))
.forEach(System.out::println);
| 問題 | 原因 | 解決 |
|---|---|---|
| listFiles() 返回 null | 非目錄、權限不足、IO 錯誤 | 判空 + try-catch |
| 符號連結導致無限循環 | Files.walk 預設不跟隨連結 | 如需跟隨加 FileVisitOption.FOLLOW_LINKS 並處理循環 |
| Windows 路徑過長 (>260) | 舊版 API 限制 | Java 10+ 原生支援、或 \\\\?\\ 前綴 |
| 隱藏檔案被包含 | 預設包含 | 加 !Files.isHidden(p) 過濾 |
| 大量檔案 OOM | collect 累積 List | 用 forEach 串流處理 |
Files.walk() Stream API**:函數式、可並行 (.parallel())、支援深度限制、過濾鏈式File.listFiles(),注意判空與棧溢位 (極深目錄)forEach 串流處理,不可 collect.parallel(),IO 密集型不建議Java 遍歷目錄已從手寫遞歸進化為 Files.walk() 一行代碼。掌握 **Stream 過濾鏈、深度限制、串流處理、異常處理**,能輕鬆應對各種檔案系統掃描需求。