383. Java IO API - Java 文件查找工具:Find 示例完整解析

383. Java IO API - Java 文件查找工具:Find 示例完整解析

這是一個用 Java 編寫的簡單文件查找工具,它模仿了 Linux 中的 find 命令,允許你通過 glob 模式查找符合特定命名規(guī)則的文件或目錄。

/**
 * Sample code that finds files that match the specified glob pattern.
 * For more information on what constitutes a glob pattern, see
 * https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob
 *
 * The file or directories that match the pattern are printed to
 * standard out.  The number of matches is also printed.
 *
 * When executing this application, you must put the glob pattern
 * in quotes, so the shell will not expand any wild cards:
 *              java Find . -name "*.java"
 */

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import static java.nio.file.FileVisitResult.*;
import static java.nio.file.FileVisitOption.*;
import java.util.*;


public class Find {

    public static class Finder
        extends SimpleFileVisitor<Path> {

        private final PathMatcher matcher;
        private int numMatches = 0;

        Finder(String pattern) {
            matcher = FileSystems.getDefault()
                    .getPathMatcher("glob:" + pattern);
        }

        // Compares the glob pattern against
        // the file or directory name.
        void find(Path file) {
            Path name = file.getFileName();
            if (name != null && matcher.matches(name)) {
                numMatches++;
                System.out.println(file);
            }
        }

        // Prints the total number of
        // matches to standard out.
        void done() {
            System.out.println("Matched: "
                + numMatches);
        }

        // Invoke the pattern matching
        // method on each file.
        @Override
        public FileVisitResult visitFile(Path file,
                BasicFileAttributes attrs) {
            find(file);
            return CONTINUE;
        }

        // Invoke the pattern matching
        // method on each directory.
        @Override
        public FileVisitResult preVisitDirectory(Path dir,
                BasicFileAttributes attrs) {
            find(dir);
            return CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Path file,
                IOException exc) {
            System.err.println(exc);
            return CONTINUE;
        }
    }

    static void usage() {
        System.err.println("java Find <path>" +
            " -name \"<glob_pattern>\"");
        System.exit(-1);
    }

    public static void main(String[] args)
        throws IOException {

        if (args.length < 3 || !args[1].equals("-name"))
            usage();

        Path startingDir = Paths.get(args[0]);
        String pattern = args[2];

        Finder finder = new Finder(pattern);
        Files.walkFileTree(startingDir, finder);
        finder.done();
    }
}

?? 功能簡介

這個程序會:

  • 遍歷指定目錄及其子目錄;
  • 使用 glob 模式匹配文件或目錄名;
  • 輸出所有匹配項的路徑;
  • 輸出匹配總數(shù)。

例如:

$ java Find . -name "*.java"

會打印當前目錄及其子目錄中所有以 .java 結尾的文件。


? 示例代碼結構詳解

1?? main() 方法:入口程序

public static void main(String[] args) throws IOException {
    if (args.length < 3 || !args[1].equals("-name"))
        usage();

    Path startingDir = Paths.get(args[0]);
    String pattern = args[2];

    Finder finder = new Finder(pattern);
    Files.walkFileTree(startingDir, finder);
    finder.done();
}
  • 接收命令行參數(shù):路徑 + -name + glob 模式。
  • 使用 Files.walkFileTree() 遍歷文件樹。
  • 調(diào)用 Finder 匹配并輸出結果。

2?? Finder 類:自定義文件訪問器

public static class Finder extends SimpleFileVisitor<Path> {

繼承 SimpleFileVisitor<Path>,重寫幾個核心方法來自定義行為:

?? 構造方法:初始化 glob 匹配器

matcher = FileSystems.getDefault().getPathMatcher("glob:" + pattern);

示例:"*.java" ? 匹配所有 Java 源文件。


?? find() 方法:核心匹配邏輯

void find(Path file) {
    Path name = file.getFileName();
    if (name != null && matcher.matches(name)) {
        numMatches++;
        System.out.println(file);
    }
}
  • 使用 matcher.matches(...) 判斷文件是否匹配;
  • 統(tǒng)計匹配個數(shù);
  • 輸出匹配路徑。

?? preVisitDirectory():遍歷目錄前的匹配邏輯

public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
    find(dir); // 匹配目錄名
    return CONTINUE;
}

不僅可以匹配文件,也能匹配目錄名稱。


?? visitFile():遍歷文件時的匹配邏輯

public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
    find(file);
    return CONTINUE;
}

對每一個文件調(diào)用 find() 方法。


?? visitFileFailed():錯誤處理

public FileVisitResult visitFileFailed(Path file, IOException exc) {
    System.err.println(exc);
    return CONTINUE;
}

如果文件訪問失敗(如權限問題),打印錯誤但不終止遍歷。


?? done():打印統(tǒng)計結果

void done() {
    System.out.println("Matched: " + numMatches);
}

在遍歷完成后顯示總共找到多少個匹配項。


?? 運行示例

$ java Find . -name "*.html"

輸出:

./index.html
./docs/help.html
Matched: 2

?? 擴展思路與練習建議

擴展功能 實現(xiàn)方法
僅查找文件,不查找目錄 visitFile() 中匹配,preVisitDirectory() 不調(diào)用 find()
過濾某些目錄(如 .git preVisitDirectory() 中判斷名稱并返回 SKIP_SUBTREE
使用正則表達式匹配 替換為 getPathMatcher("regex:" + pattern)
跟蹤符號鏈接 使用 EnumSet.of(FileVisitOption.FOLLOW_LINKS) 作為 walkFileTree() 參數(shù)
查找結果寫入文件 System.out.println(...) 替換為寫入 BufferedWriter

?? 小貼士:PathMatcher 注意事項

  • 僅文件名匹配:要記得用 file.getFileName() 而不是整個 Path,否則路徑中目錄部分也會被匹配。
  • 通配符需要加引號:如 "*.java",否則 shell 會提前展開通配符。

?? 錯誤處理建議

  • 可以改進 visitFileFailed() 的行為,比如記錄失敗日志或重試。
  • 使用 try-catch 包裝 walkFileTree(),處理整體異常。

? 結語

這個 Find 示例是理解 Java 文件遍歷與模式匹配機制的絕佳入門材料。它涵蓋了:

  • walkFileTree 的用法;
  • 文件訪問器的重寫方式;
  • PathMatcher 的實際應用;
  • glob 模式的基礎。

在實際項目中,結合該示例可構建自己的文件過濾工具、批量處理腳本或配置管理工具。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容