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用作宽度遍历中的队列。

posted @ 2020-01-15 22:04  allMayMight  阅读(1143)  评论(0编辑  收藏  举报