首页 > 编程语言 >Java遍历文件夹

Java遍历文件夹

时间:2022-10-02 22:56:25浏览次数:81  
标签:files 遍历 Java System 文件夹 file println stack

Java遍历文件夹


简单写了一个打印目录下所有文件以及文件夹的代码,类比于树的遍历,写了深度优先和广度优先的遍历。并且还写了个JDK1.7接口提供的的版本。

深度广度遍历都用到的双端队列(ArrayDeque),不了解双端队列的话可以去学习一下。我简单说一下,双端队列既可以用作队列,也可以用作栈,而且效率比较高。


1.1 深度优先遍历

使用栈存储File对象,出栈后,输出file信息,若是文件夹,就将文件夹下的子文件以及子文件夹全部压入栈,栈空则遍历完成。

代码

    //深度优先遍历 Depth First Search
    //使用栈
    static void dfs(File file) {
        if (file == null || !file.exists()) {
            return;
        }

        final Deque<File> stack = new ArrayDeque<>();
        stack.push(file);

//        stack.pop();
//        stack.pollFirst();
        while ((file = stack.pollFirst()) != null) {
            System.out.println(file);
/*
            if (!file.exists()) {
                //文件存在,但系统拒绝访问
            }
*/
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                if (files == null) {
                    System.err.println(file + "\t文件夹访问受限,跳过");
                    continue;
                }
                for (int filesLength = files.length, i = filesLength - 1; i >= 0; i--) {
                    stack.push(files[i]);
                }
            }
        }

    }

此处注意:

  1. 使用file.listFiles()得到的子文件以及文件夹不一定能访问。若调用file.exists()返回为false则为无法访问。
  2. file为文件夹,则file.listFiles()应返回File数组。此处做判断是为了程序的鲁棒性。

1.2 广度优先遍历

使用队列储存File对象,利用队列先入先出的特性,遍历文件夹。大学时,我就用C语言写了一个层次遍历二叉树的实现,只是当时遍历出的结果没有分层。这次在此基础上,使用list记录了每一层的文件及文件夹个数,并输出。

代码

    //广度优先遍历 Breath First Search
    //使用队列
    static List<Integer> bfs(File file) {
        if (file == null || !file.exists()) {
            return Collections.emptyList();
        }

        final Queue<File> queue = new ArrayDeque<>();
        queue.offer(file);

        //每一层包含元素的个数
        final List<Integer> list = new ArrayList<>();

        //i 循环次数
        //j 层数
        //n 该层包含元素个数
        int i = 0, j = 0, n = 0;
        list.add(1);

        while ((file = queue.poll()) != null) {
            System.out.println(file);
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                if (files == null) {
                    System.err.println(file + "\t文件夹访问受限,跳过");
                    continue;
                }
                n += files.length;
                Arrays.stream(files).forEach(queue::offer);
            }

            i++;
            if (i == list.get(j)) {
                //遍历一层结束
                list.add(n);
                i = 0;
                j++;
                n = 0;
            }
        }

1.3 Java提供 Files.walkFileTree()

这个就没什么好说的了,属于深度优先遍历。大量文件及文件夹时,使用此方法遍历效果十分好。

代码

    //nio
    static void nio(Path path) throws IOException {

        Files.walkFileTree(path, new FileVisitor<Path>() {
            //访问文件夹之前调用此方法
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                System.out.println(dir);
//                System.out.println(attrs);
                return FileVisitResult.CONTINUE;
            }

            //访问文件时调用此方法
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                System.out.println(file);
//                System.out.println(attrs);
                return FileVisitResult.CONTINUE;
            }

            //访问文件失败时调用此方法
            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                System.err.print(file + "\t文件访问受限: ");
                if (exc == null) {
                    System.err.println("未知错误");
                } else {
                    System.err.println(exc);
//                    throw exc;
                }
                return FileVisitResult.CONTINUE;

            }

            //访问文件夹之后调用此方法
            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
//                System.out.println(dir);
                if (exc != null) {
                    System.err.println(dir + "\t文件夹访问受限,跳过" + exc);
//                    throw exc;
                }
                return FileVisitResult.CONTINUE;
            }
        });
    }


删除文件夹的想法


然后我又想着,既然遍历都做完了,要不再试试删除。三个方法。

  1. 使用Java提供 Files.walkFileTree()。这个是真的便利,只需要在访问文件时和文件夹后调用删除方法即可。
  2. 使用递归,这个也是相当简单粗暴的方法了。遍历文件夹就可以用递归,代码也时相当简单就不做了。
  3. 和深度优先遍历相似,删除文件之后,再删除文件夹。

2. 删除文件夹

深度优先遍历,先上代码:

    static void delete(File file) {
        if (file == null || !file.exists()) {
            return;
        }

        Deque<File> stack = new ArrayDeque<>();
        stack.push(file);

        while (!stack.isEmpty()) {
            file = stack.peek();
            if (!file.exists()) {
                System.out.println(file + " 文件无法访问");
//                stack.poll();
//                continue;
            }
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                if (files != null && files.length != 0) {
                    //为了代码的简洁,选择全部入栈,不做文件、文件夹的判断
                    for (int filesLength = files.length, i = filesLength - 1; i >= 0; i--) {
                        stack.push(files[i]);
                    }
                    continue;
                }
            }
            //file是文件,或空文件夹时,直接删除
            if (file.delete())
                System.out.println(file + " 删除成功");
            else {
                System.out.println(file + " 删除失败");
                return;//重点标记
            }
            stack.poll();

        }
    }

去掉代码中重点标记的哪一行return,实际运行此代码会发现一个问题,若有一个文件无法成功删除,便会陷入出栈之后再入栈的死循环当中。

即便时在重点标记上加上一个“删除失败后,出栈File对象,到下个要删除的文件夹”的逻辑后,也不能排除两个文件中文件都无法删除而再度陷入循环的困境中。

此时就需要改变入栈的元素,记录下子文件及文件夹的数量,来判断出栈了。至于这个坑,就不一行会埋上了。


最后附上全部代码(包含import)

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;

public class FolderTraversal {
//    private static final Deque<File> deque = new ArrayDeque<>();

    //深度优先遍历 Depth First Search
    //使用栈
    static void dfs(File file) {
        if (file == null || !file.exists()) {
            return;
        }

        final Deque<File> stack = new ArrayDeque<>();
        stack.push(file);

//        stack.pop();
//        stack.pollFirst();
        while ((file = stack.pollFirst()) != null) {
            System.out.println(file);
/*
            if (!file.exists()) {
                //文件存在,但系统拒绝访问
            }
*/
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                if (files == null) {
                    System.err.println(file + "\t文件夹访问受限,跳过");
                    continue;
                }
                for (int filesLength = files.length, i = filesLength - 1; i >= 0; i--) {
                    stack.push(files[i]);
                }
            }
        }

    }

    static void delete(File file) {
        if (file == null || !file.exists()) {
            return;
        }

        Deque<File> stack = new ArrayDeque<>();
        stack.push(file);

        while (!stack.isEmpty()) {
            file = stack.peek();
            if (!file.exists()) {
                System.out.println(file + " 文件无法访问");
//                stack.poll();
//                continue;
            }
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                if (files != null && files.length != 0) {
                    //为了代码的简洁,选择全部入栈,不做文件、文件夹的判断
                    for (int filesLength = files.length, i = filesLength - 1; i >= 0; i--) {
                        stack.push(files[i]);
                    }
                    continue;
                }
            }
            //file是文件,或空文件夹时,直接删除
            if (file.delete())
                System.out.println(file + " 删除成功");
            else {
                System.out.println(file + " 删除失败");
                return;
            }
            stack.poll();

        }
    }

    //广度优先遍历 Breath First Search
    //使用队列
    static List<Integer> bfs(File file) {
        if (file == null || !file.exists()) {
            return Collections.emptyList();
        }

        final Queue<File> queue = new ArrayDeque<>();
        queue.offer(file);

        //每一层包含元素的个数
        final List<Integer> list = new ArrayList<>();

        //i 循环次数
        //j 层数
        //n 该层包含元素个数
        int i = 0, j = 0, n = 0;
        list.add(1);

        while ((file = queue.poll()) != null) {
            System.out.println(file);
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                if (files == null) {
                    System.err.println(file + "\t文件夹访问受限,跳过");
                    continue;
                }
                n += files.length;
                Arrays.stream(files).forEach(queue::offer);
            }

            i++;
            if (i == list.get(j)) {
                //遍历一层结束
                list.add(n);
                i = 0;
                j++;
                n = 0;
            }

        }

/*
        queue.add(file);
        queue.remove();
*/
        System.out.println(list);
        return list;
    }

    //nio
    static void nio(Path path) throws IOException {

        Files.walkFileTree(path, new FileVisitor<Path>() {
            //访问文件夹之前调用此方法
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                System.out.println(dir);
//                System.out.println(attrs);
                return FileVisitResult.CONTINUE;
            }

            //访问文件时调用此方法
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                System.out.println(file);
//                System.out.println(attrs);
                return FileVisitResult.CONTINUE;
            }

            //访问文件失败时调用此方法
            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                System.err.print(file + "\t文件访问受限: ");
                if (exc == null) {
                    System.err.println("未知错误");
                } else {
                    System.err.println(exc);
//                    throw exc;
                }
                return FileVisitResult.CONTINUE;

            }

            //访问文件夹之后调用此方法
            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
//                System.out.println(dir);
                if (exc != null) {
                    System.err.println(dir + "\t文件夹访问受限,跳过" + exc);
//                    throw exc;
                }
                return FileVisitResult.CONTINUE;
            }
        });
    }

    public static void main(String[] args) throws IOException {
//        long start = System.currentTimeMillis();

        //java中,链接是一个文件 xxx.lnk
        //  isFile()         判断为true
        //  isDirectory()    判断为false
        File file = new File("files");
//        dfs(file);//103322 59316
//        bfs(file);//98156 67997

//        Path path = Paths.get("");
//        nio(path);//30058  17460

//        long end = System.currentTimeMillis();
//        System.out.println(end - start);
    }
}

标签:files,遍历,Java,System,文件夹,file,println,stack
From: https://www.cnblogs.com/pong137/p/16749687.html

相关文章

  • 9月30Java类与对象中动手动脑
    类与对象定义了一组大体相似的对象。一个类所包含的方法和数据描述一组对象的共同行为和属性对象则是类的具体化,是类的实例。类通过派生类可以有子类,同样也可以有父类,形......
  • java学习之:类和对象、语句块、方法、递归结构!
    语句块和方法语句块语句块确定了局部变量的作用域。语句块嵌套,但是不能在两个嵌套的块内声明同名的变量。语句块可以使用语句块外的变量,语句块中定义的变量作用域只限于语句......
  • javascript>=和<=
    一个条件都不满足为false,至少满足一个条件为truevara=10console.log(a>10);//false;console.log(a<10);//false;console.log(a==10);//trueconsole.log(a>=10);//true1......
  • 【Java】01基础-05 方法
    1.方法概述1.1方法的概念方法(method)是将具有独立功能的代码块组织成为一个整体,使其具有特殊功能的代码集注意:方法必须先创建才可以使用,该过程成为方法定义方法创建后并不......
  • 【Java】01基础-04数组
    1.数组1.1数组介绍数组就是存储数据长度固定的容器,存储多个数据的数据类型要一致。1.2数组的定义格式1.2.1第一种格式数据类型[]数组名示例:int[]arr;double[]......
  • 15分钟精通二叉树,二叉树的先序,中序,后序,层次遍历顺序
    学习目标:......
  • Java设计模式 —— 原型模式
    7原型模式7.1原型模式概述PrototypePattern:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。原型模式的工作原理:将一个原型对象传给创建......
  • 试验:Java字段初始化的规律
    packagetest2;publicclassInitializeBlockDemo{ /** *@paramargs */ publicstaticvoidmain(String[]args){ InitializeBlockClassobj=newIni......
  • Java方法详解
    JAVA方法详解Symtem.out.println()类对象方法JAVA方法是语句的集合,它们在一起执行一个功能方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在......
  • 数据结构与算法【Java】09---多路查找树
    目录前言1、二叉树与B树1.1、二叉树的问题分析1.2、多叉树1.3、B树的基本介绍2、2-3树2.1、2-3树简介2.2、2-3树应用案例2.3、补充3、B树、B+树和B*树3.1、B树的简......