Java 遍歷目錄下的所有文件(深度優先遍歷,寬度優先遍歷)


遞歸方法

import java.io.File;
import java.util.*;

public class test3 {
    public static List<File> recurseDirs(String start,String regex) {
        return recurseDirs(new File(start), regex);
    }

    public static List<File> recurseDirs(String start) {
        return recurseDirs(new File(start), ".*");
    }

    public static List<File> recurseDirs(File startDir) {
        return recurseDirs(startDir, ".*");
    }
    
    public static List<File> recurseDirs(File startDir, String regex) {
        List<File> result = new ArrayList<File>();
        if (startDir.listFiles() == null) {//防止主函數調用時給出路徑不是一個有效的目錄
            System.out.println("這不是一個有效的目錄");
            return result;//直接返回空的list
        }

        for(File item : startDir.listFiles()) {
            if(item.isDirectory()) {
                result.add(item);
                result.addAll(recurseDirs(item));
            } else {
                if(item.getName().matches(regex))
                    result.add(item);
            }
        }
        return result;
    }

    public static void main(String[] args) {
        List<File> files = recurseDirs("E:/影視作品");

        for(File i:files) {
            System.out.println(i);
        }
    }
}

其實這個例子來自JAVA編程思想——18.1.2目錄實用工具——Directory類。看了書中代碼着實覺得這種遞歸實現太優雅了,所以我改了改變成了自己的實現。

  • public static List<File> recurseDirs(File startDir, String regex)這個簽名的方法才是主要的函數,其他的都是重載版本,regex參數就是你要設置的正則表達式,如果你設置了regex形參,那么只有符合該regex的File才會返回。
  • 關於遞歸設計,書中用的是一個作者自己寫的一個TreeInfo靜態內部類,它實現了一個addAll方法,但實際上它內部也用到了List接口的addAll,所以我這里就改成了使用ArrayList來存儲File對象。

這個遞歸的精妙之處:

  • 首先多虧了List接口里自帶addAll這個接口,要是沒有這個addAll,那么result用File[]作為類型也一樣(recurseDirs的返回值也改成File[]),然后單獨寫一個靜態方法,可以是這樣的簽名public static File[] addAll(File[] a, File[] b),然后這句result.addAll(recurseDirs(item));改成result = addAll(result, recurseDirs(item))
  • 只要是調用了遞歸方法體,傳進來的startDir必定是一個目錄(isDirectory返回true),這是由循環中調用遞歸的前提判斷來保證的。
  • 在循環中,如果發現循環變量item是一個當前目錄下的文件,那么執行else分支,不會調用到遞歸函數;如果發現循環變量item是一個當前目錄下的子目錄,那么執行if分支,會調用到遞歸函數,調用前先添加這個子目錄。

其他:

  • listFiles返回一個File[],如果調用的File不是一個有效的目錄,返回null。
  • if (startDir.listFiles() == null)分支只是為了防止主函數調用時給出路徑不是一個有效的目錄,如果不是有效目錄且沒有這個判斷,下面的循環會拋出空指針異常。只要主函數給的有效目錄,之后就不會出錯了。

遞歸+限制目錄深度

import java.io.File;
import java.util.*;

public class test4 {
    public static List<File> recurseDirs(File startDir, int count) {
        List<File> result = new ArrayList<File>();
        if (count == 0) {
            return result;//直接返回空的list
        }
        if (startDir.listFiles() == null) {//防止主函數調用時給出路徑不是一個有效的目錄
            System.out.println("這不是一個有效的目錄");
            return result;//直接返回空的list
        }

        for(File item : startDir.listFiles()) {
            if(item.isDirectory()) {
                result.add(item);
                result.addAll(recurseDirs(item, count - 1));
            } else {
                result.add(item);
            }
        }
        return result;
    }

    public static void main(String[] args) {
        List<File> files = recurseDirs(new File("E:/影視作品"),2);
        for(File i:files) {
            System.out.println(i);
        }
    }
}

給recurseDirs加一個參數代表遞歸目錄的深度,為2時代表深度為2。主函數中,給的目錄下的所有文件或子目錄算是1的深度。

主函數中,給的目錄是E:/影視作品,打印結果如下:
在這里插入圖片描述
可見深度只能到2。

BFS

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class test5 {
    public static List<File> BFS(File startDir) {
        List<File> result = new ArrayList<File>();
        if (startDir.listFiles() == null) {//防止主函數調用時給出路徑不是一個有效的目錄
            System.out.println("這不是一個有效的目錄");
            return result;//直接返回空的list
        }
        LinkedList<File> queue = new LinkedList<>();//用作隊列
        queue.addAll(Arrays.asList(startDir.listFiles()));//給隊列起個頭
        while (!queue.isEmpty()) {//只要隊列不為空
            //取出隊列的第一個元素
            File item = queue.removeFirst();
            if (item.isDirectory())//如果當前元素是目錄
                queue.addAll(Arrays.asList(item.listFiles()));//往隊列里加入目錄下的所有文件

            result.add(item);//總是加入當前元素
        }
        return result;
    }

    public static void main(String[] args) {
        List<File> files = BFS(new File("E:/影視作品"));
        for(File i:files) {
            System.out.println(i);
        }
    }
}

遞歸是深度遍歷,既然深度遍歷用了,那再試試寬度遍歷唄。使用LinkedList用作寬度遍歷中的隊列。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM