# File类

# File类的概述

java.io.File类是文件和目录路径名的抽象表示形式。java把电脑中的文件和目录封装成了一个File类,我们可以使用File类对文件和文件夹进行操作:

  • 创建一个文件或文件夹
  • 删除一个文件或文件夹
  • 获取一个文件或文件夹
  • 判断一个文件或文件夹
  • 对文件夹进行遍历
  • 获取文件的大小

File类是一个与系统无关的类,任何的操作系统都可以使用这个类中的方法。在File类中,有三个重要概念:

  • file:文件
  • directory:文件夹/目录
  • path:路径

# File类的静态成员变量

静态成员变量 说明
File.pathSeparator 与系统有关的路径分隔符,为了方便表示为字符串
File.pathSeparatorChar 与系统有关的路径分隔符
File.separator 与系统有关的默认名称分隔符,为了方便表示为字符串
File.separatorChar 与路径有关的路径分隔符
  • 默认情况下,windows系统的默认路径分隔符为;,linux系统默认路径分隔符为:
  • 默认情况下,windows系统的默认名称分隔符为\,linux系统默认名称分隔符为/

# 绝对路径和相对路径

路径不区分大小写,可以分为两种路径:绝对路径和相对路径

  • 绝对路径:是一个完整的路径,以盘符开始的路径。
  • 相对路径:是一个简化的路径,相对于当前项目的根目录,如果使用当前项目的根目录,则路径可以简化。

# File类的构造方法

  • File(String pathname):通过将给定路径名字符串转换为抽象路径名来创建一个新File实例。

    参数 说明
    String pathname String pathname:字符串的路径名称
    路径可以是以文件结尾或文件夹结尾
    路径可以是相对路径或绝对路径
    路径可以是存在或不存在
    创建File对象,只是把字符串路径封装为File对象,不考虑路径的真假情况
  • File(String parent, String child):根据parent路径名字字符串和child路径名字字符串创建了一个新File实例。

参数
String parent, String child 把路径分成了两部分
String parent:父路径
String child:子路径
好处:
父路径和子路径,可以单独书写,使用起来灵活;父子路径都可以变化
  • File(File parent, String child):根据parent抽象路径和child路径名字字符串创建一个新File实例。

    参数
    File parent, String child 把路径分成了两部分
    File parent:父路径
    String child:子路径
    好处:
    父路径和子路径,可以单独书写,使用起来灵活;父路径和子路径都可以变化
    父路径是File类型,可以使用File的方法对路径进行一些操作再使用路径创建对象

# File类获取功能

  • public String getAbsolutePath():返回此File的绝对路径名字符串,获取构造方法中传递的路径,无论是绝对路径还是相对路径,返回的都是绝对路径。
  • public String getPath():将此File转换为路径名字符串,即获取构造方法中传递的路径,传递的路径是什么样就返回什么样的路径。 public String getName():返回由此File表示的文件或文件夹(目录)的名称,获取的就是构造方法传递路径的结尾部分(文件,文件夹) public long length():返回由此File表示的文件的长度(大小),获取的构造方法指定的文件的大小,以字节为单位。注意,文件夹是没有大小概念的,不能获取文件夹大小。如果构造方法中给出的路径不存在,那么length方法返回零

# File判断功能

  • public boolean exists():此File表示的文件或目录是否实际存在。用于判断构造方法中的路径是否存在,存在则为true,不存在则为false。

  • public boolean isDirectory():用于判断构造方法中给定的路径是否以文件夹结尾。如果是返回true,否则返回false

  • public boolean isFile():此File表示的是否为文件,用于判断构造方法中给定的路径是否以文件结尾。如果是返回true,否则返回false。

isDirectory()isFile()使用的前提是路径必须存在,否则都返回false。由于电脑中只有文件或文件夹,因此,这两个方法是互斥的。

# File类创建删除功能

  • public boolean createNewFile():当且仅当具有该名称的文件不存在时,创建一个新的空文件。

    说明 注意事项
    当且仅当具有该名称的文件不存在时,创建一个新的空文件。
    创建文件的路径和名称在构造方法中给出,
    返回值:
    true,文件不存在,创建文件返回true;
    false,文件存在,不会创建
    此方法只能创建文件,不能创建文件夹,
    创建文件的路径必须存在,否则会抛出异常。
  • public boolean delete():删除由此File表示的文件或目录。

    说明 注意事项
    此方法可以删除构造方法路径中给出的文件/文件夹
    返回值:
    true:文件/文件夹删除成功;
    false:文件夹中有内容,不会删除,返回false;构造方法中路径不存在false;
    该方法是直接在硬盘删除文件/文件夹,不走回收站,删除要谨慎。
  • public boolean mkdir():创建由此File表示的目录。

    说明 注意事项
    创建文件夹的路径和名称在构造方法中给出,
    返回值:
    true,文件夹不存在,创建文件夹返回true;
    false,文件夹存在,不会创建;构造方法中给出的路径不存在返回false
    此方法只能创建文件夹,不能创建文件
  • public boolean mkdirs():创建由此File表示的目录,包括任何必须但不存在的父目录

# File类目录的遍历功能

File类遍历目录(文件夹)的方法有两个:

  • public String[] list():返回一个String数组,表示该File目录中的所有子文件或目录。

  • public File[] listFiles():返回一个File数组,表示该File目录中的所有子文件或目录。

    说明
    list()listFiles()遍历的是构造方法中给出的目录,
    如果构造方法给出的目录的路径不存在,会抛出空指针异常。
    如果构造方法给出的路径不是一个目录,也会抛出空指针异常。

# 递归

# 递归的定义

指在当前方法中自己调用自己的情况

# 递归的分类

递归分为两种:直接递归和间接递归

  • 直接递归:方法直接调用自己
  • 间接递归:A方法调用B方法,B方法调用C方法,C方法调用A方法,这种不直接调用自己的递归,称为间接递归。

# 递归的注意事项

  • 递归一定要有一定的条件限定,保证递归能够停下来,否则会发生栈内存溢出。
  • 在递归中虽然有限定条件,但是递归的次数不宜过多,否则也会发生栈内存溢出。
  • 构造方法,要禁止递归。

# 递归遍历多级目录

为了更好理解递归,我们选定目录E:\文档,遍历其子目录及文件。

package com.example.demo;

import java.io.File;

public class FileListDemo {

    public static void main(String[] args) {
        File file = new File("E:\\文档");
        getAllFiles(file);
    }

    public static void getAllFiles(File dir) {
        System.out.println(dir);
        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                getAllFiles(file); //递归调用
            } else {
                System.out.println(file);
            }
        }
    }
}

# 递归遍历特定文件搜索

在这个例子中,我们需要递归搜索以.pdf结尾的文件,因此,我们在else语句中增加判断是否以.pdf结尾的文件,再打印输出。

package com.example.demo;

import java.io.File;

public class FileListDemo {

    public static void main(String[] args) {
        File file = new File("E:\\文档");
        getAllFiles(file);
    }

    public static void getAllFiles(File dir) {
        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                getAllFiles(file);
            } else {
                if(file.getName().endsWith(".pdf")){
                    System.out.println(file);
                }
            }
        }
    }
}

# 文件过滤器接口

File类中有两个和listFiles重载的方法,方法的参数传递的就是过滤器。

# FileFilter过滤器接口

使用FileFilter过滤器重载的方法为File[] listFiles(FileFilter filter),过滤器的详情如下:

方法 作用 参数
File[] listFiles(FileFilter filter) 它是用于抽象路径名(File对象)的过滤器,主要作用是,
用来过滤文件(File对象)
FileFilter接口内部包含一个boolean accept(File pathname),测试抽象路径名是否包含在某个路径名列表,其参数是使用listFiles方法遍历目录得到的每一个文件对象。

其中,listFiles方法一共做了两件事:

  • listFiles方法会对构造方法中传递的目录进行遍历,获取目录中的每一个文件/文件夹,并封装为File对象。
  • listFiles方法会调用参数传递的过滤器中的方法accept
  • listFiles方法会把遍历得到的每一个File对象,传递给accept方法的参数pathname

accept方法返回true时,listFiles方法就将该File对象添加到返参的File数组里。否则,不添加到返参的File数组里。

# FilenameFilter过滤器接口

方法 作用 参数
File[] listFiles(FilenameFilter filter) 它的作用是用于过滤文件名 其内部包含boolean accept(File dir,String name) 测试指定文件是否包含在某一文件列表中,File dir是构造方法中传递的被遍历的目录,String name是使用listFiles方法遍历目录获取的每一个文件/文件夹名称

注意:两个过滤器接口都没有实现类,需要自行编写实现类,重写过滤的方法accept,在方法中自己定义过滤的规则。

# 使用FileFiter过滤器重写文件搜索

首先,我们需要实现FileFilter接口,重写其accept方法。在这个过滤方法中,对于目录我们直接返回true,让其在下一段代码中继续遍历其中的文件,对于文件,则判断是否是以.pdf结尾。

package com.example.demo;

import java.io.File;
import java.io.FileFilter;

public class FileFilterImpl implements FileFilter {
    @Override
    public boolean accept(File pathname) {
        // 如果pathname是一个文件夹,则返回true,继续遍历文件夹
        if(pathname.isDirectory()) {
            return true;
        }
        return pathname.getName().toLowerCase().endsWith(".pdf");
    }
}

接着,我们将FileFilterImpl实现类作为参数传递给listFiles方法。

package com.example.demo;

import java.io.File;

public class FileFiterDemo {

    public static void main(String[] args) {
        File file = new File("E:\\文档");
        getAllFiles(file);
    }

    public static void getAllFiles(File dir) {
        File[] files = dir.listFiles(new FileFilterImpl());
        for (File file : files) {
            if (file.isDirectory()) {
                getAllFiles(file);
            } else {
                System.out.println(file);
            }
        }
    }
}

运行程序,我们成功搜索出.pdf结尾的文件。

# 使用FilenameFilter过滤器重写文件搜索

下面,我们继续使用FilenameFilter来完成文件搜索功能。这次,我们使用匿名内部类,逻辑和刚才一致。

package com.example.demo;

import java.io.File;
import java.io.FilenameFilter;

public class FilenameFilterDemo {

    public static void main(String[] args) {
        File file = new File("E:\\文档");
        getAllFiles(file);
    }

    public static void getAllFiles(File dir) {
        File[] files = dir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                // 判断其是否是文件夹或者其是否以.pdf结尾
                return new File(dir, name).isDirectory() || name.toLowerCase().endsWith(".pdf");
            }
        });
        for (File file : files) {
            if (file.isDirectory()) {
                getAllFiles(file);
            } else {
                System.out.println(file);
            }
        }
    }
}

类似地,可以使用匿名内部类代替原有的FileFilter实现方法。

# 使用Lambda表达式实现文件搜索

在JDK8中,我们可以使用Lambda表达式简化代码,将上面代码中的这段代码

File[] files = dir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                // 判断其是否是文件夹或者其是否以.pdf结尾
                return new File(dir, name).isDirectory() || name.toLowerCase().endsWith(".pdf");
            }
        });

简化为:

 File[] files = dir.listFiles((d,name)-> new File(d,name).isDirectory() || name.toLowerCase().endsWith(".pdf"));

其完整实现如下:

package com.example.demo;

import java.io.File;
import java.io.FilenameFilter;

public class FilenameFilterLDemo {


    public static void main(String[] args) {
        File file = new File("E:\\文档");
        getAllFiles(file);
    }

    public static void getAllFiles(File dir) {
        File[] files = dir.listFiles((d,name)-> new File(d,name).isDirectory() || name.toLowerCase().endsWith(".pdf"));
        for (File file : files) {
            if (file.isDirectory()) {
                getAllFiles(file);
            } else {
                System.out.println(file);
            }
        }
    }
}
LastUpdated: 3/20/2021, 11:37:24 AM