首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 遞歸遍歷目錄獲取所有檔案完整範例

     編輯:Java 相關知識

遞歸實現 (經典 File API)

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);
}

Java 7+ NIO.2 現代寫法 (推薦)

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) 過濾
大量檔案 OOMcollect 累積 List用 forEach 串流處理

效能建議

  • **現代專案首選 Files.walk() Stream API**:函數式、可並行 (.parallel())、支援深度限制、過濾鏈式
  • **舊版維護**用遞歸 File.listFiles(),注意判空與棧溢位 (極深目錄)
  • **超大目錄樹** (>10萬檔) 必須用 forEach 串流處理,不可 collect
  • **並行處理** CPU 密集型操作 (如計算檔案 hash) 可 .parallel(),IO 密集型不建議

總結

Java 遍歷目錄已從手寫遞歸進化為 Files.walk() 一行代碼。掌握 **Stream 過濾鏈、深度限制、串流處理、異常處理**,能輕鬆應對各種檔案系統掃描需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved