Java基础快速入门: File类与IO流基础

本文纲要

  1. FileIO概述
  2. File类的构造方法
  3. 绝对路径与相对路径
  4. File的创建功能
  5. File的删除方法
  6. File的判断与获取方法
  7. File的高级获取方法:listFiles
  8. 项目代码结构
  9. 综合练习
    练习1:在指定目录中创建文件
    练习2:递归删除多级文件夹
    练习3:统计文件夹中每种文件出现的次数

File和IO概述

在Java中,我们经常需要对硬盘上的文件进行读写操作,实现数据的永久化存储。例如:保存用户配置、导出报表、日志记录等。

回想一下,使用变量、数组或集合存储数据,当程序运行结束后所有数据都会丢失。而借助硬盘这一硬件,我们可以在程序退出后依然保留数据。在操作系统中,我们通常对硬盘进行读和写两种操作,但在读写之前,必须先知道文件在哪儿。
IO流:负责将数据从本地文件读取到内存,或者将内存中的数据写入本地文件,实现永久存储。
File类:用于描述要操作的文件或文件夹的路径,同时也能对文件/文件夹本身进行创建、删除等操作。

简言之:File 定位文件位置,IO 流负责读写数据。

File类的构造方法

java.io.File 类是文件和目录路径名的抽象表示。
它封装的对象可以是存在的路径,也可以是不存在的路径。学习一个类,先从构造方法开始。

File 提供了三种常用构造:

构造方法说明
File(String pathname)将字符串路径转换为File对象
File(String parent, String child)拼接父路径和子路径创建File对象
File(File parent, String child)拼接父File对象与子路径创建File对象

为什么要把字符串表示的路径变成File对象?
因为 String 类本身没有操作文件的方法(如删除、创建等),而 File 类提供了丰富的方法。
因此我们需要将路径包装成File对象来调用这些方法

下面是三种构造方法的演示代码:

// FileDemo1.java 
public class FileDemo1 {
    public static void main(String[] args) {
        method1();
        method2();
        method3();
    }
 
    // 1. File(String pathname)
    private static void method1() {
        String path = "C:\\wb\\a.txt";
        File file = new File(path);
        // 将字符串路径封装为File对象,以便使用File类的方法 
        System.out.println(file);  // C:\wb\a.txt 
    }
 
    // 2. File(String parent, String child) -- 路径拼接 
    private static void method2() {
        String path1 = "C:\\wb";
        String path2 = "a.txt";
        File file = new File(path1, path2);
        System.out.println(file);  // C:\wb\a.txt 
    }
 
    // 3. File(File parent, String child) -- 父File + 子路径 
    private static void method3() {
        File file1 = new File("C:\\wb");
        String path = "a.txt";
        File file = new File(file1, path);
        System.out.println(file);  // C:\wb\a.txt 
    }
}

应用场景:

  • 第一种构造:当一个完整路径字符串需要被操作时使用。
  • 第二/三种构造:多用于路径拼接,例如已知目录和文件名进行组合。

绝对路径与相对路径

Java中的路径分为两类:

  • 绝对路径:从盘符开始,位置固定不变。例如 D:\wb\a.txt。
  • 相对路径:相对当前项目而言,没有盘符开头。例如 a.txt 表示当前项目根目录下的文件。

代码示例

// FileDemo2.java 
public class FileDemo2 {
    public static void main(String[] args) {
        // 绝对路径:固定指向D盘下的文件 
        File file1 = new File("D:\\wb\\a.txt");
 
        // 相对路径:当前项目根目录下的a.txt 
        File file2 = new File("a.txt");
 
        // 相对路径:当前项目下指定模块中的a.txt 
        File file3 = new File("filemodule\\a.txt");
    }
}

注:相对路径的参照物是“当前项目”。
如果要把文件放在模块内部,需要加上模块名。

File的创建功能

File类提供了三个创建方法:

方法说明
boolean createNewFile()创建一个新文件,若已存在则返回false
boolean mkdir()创建单级文件夹,不能创建多级
boolean mkdirs()创建多级文件夹(也可创建单级)

注意点总结 (来自注释与实验):
createNewFile 不管调用者的名称是否有后缀,只能创建文件;若文件所在目录不存在,会抛出 IOException
mkdir 只能创建单级文件夹;即使名称带后缀,也只能创建文件夹。
mkdirs 可以创建单级或多级文件夹;不管调用者有没有后缀,都只创建文件夹。

代码演示

// FileDemo3.java 
public class FileDemo3 {
    public static void main(String[] args) throws IOException {
        method1(); // createNewFile 
        method2(); // mkdir 
        // 演示 mkdirs 
        File file = new File("C:\\wb\\aaa.txt");
        boolean result = file.mkdirs();
        System.out.println(result);  // true 
    }
 
    // createNewFile:只能创建文件 
    private static void method1() throws IOException {
        // 假设C:\wb\aaa 不存在 
        File file1 = new File("C:\\wb\\aaa");
        boolean result1 = file1.createNewFile();
        System.out.println(result1);
        // 即使名称为aaa,仍然创建的是一个无后缀的文件 
    }
 
    // mkdir:只能创建单级文件夹 
    private static void method2() {
        File file = new File("C:\\wb\\aaa.txt");
        boolean result = file.mkdir();
        System.out.println(result);
        // 即使名称为aaa.txt,仍会创建名为"aaa.txt"的文件夹 
    }
}

补充:mkdirs 底层会先尝试调用 mkdir,如果创建单级失败再递归创建多级,因此开发中一般直接使用 mkdirs 即可。

File的删除方法

boolean delete() 用于删除文件或空文件夹。

注意点:

  1. 删除不走回收站,直接从硬盘移除,不可恢复。
  2. 如果删除的是文件,则直接删除。
  3. 如果删除的是文件夹,只能删除空文件夹。
  4. 若想删除有内容的文件夹,需先递归删除内部所有内容,再删除该文件夹自身。

代码演示

// FileDemo4.java 
public class FileDemo4 {
    public static void main(String[] args) {
        method1();                // 删除文件 
        // 删除空文件夹示例 
        File file = new File("C:\\wb");
        boolean result = file.delete();
        System.out.println(result);
    }
 
    private static void method1() {
        File file = new File("C:\\wb\\a.txt");
        boolean result = file.delete();
        System.out.println(result);
    }
}

File的判断与获取方法

方法说明
boolean isFile()判断是否为文件
boolean isDirectory()判断是否为文件夹
boolean exists()判断文件或文件夹是否存在
String getName()获取文件或文件夹名称(文件包含后缀)

代码演示

// FileDemo5.java 
public class FileDemo5 {
    public static void main(String[] args) {
        method1(); // isFile & isDirectory (文件)
        method2(); // isFile & isDirectory (文件夹)
        method3(); // exists 
 
        // getName 演示 
        File file = new File("a.txt");
        System.out.println(file.getName());     // a.txt 
        File file1 = new File("C:\\wb");
        System.out.println(file1.getName());    // wb 
    }
 
    private static void method1() {
        File file = new File("C:\\wb\\a.txt");
        System.out.println(file.isFile());       // true 
        System.out.println(file.isDirectory());  // false 
    }
 
    private static void method2() {
        File file = new File("C:\\wb");
        System.out.println(file.isFile());       // false 
        System.out.println(file.isDirectory());  // true 
    }
 
    private static void method3() {
        File file = new File("a.txt");
        System.out.println(file.exists());       // false(假设不存在)
    }
}

File的高级获取方法:listFiles

File[] listFiles() 返回目录下所有文件和文件夹的File对象数组(包括隐藏文件/文件夹)。
注意事项

调用者情况返回值
调用者是文件返回 null
调用者是空文件夹返回长度为0的数组
调用者是有内容的文件夹返回包含所有子文件和子文件夹的数组
调用者不存在无权限返回 null

代码演示

// FileDemo6.java 
public class FileDemo6 {
    public static void main(String[] args) {
        File file = new File("D:\\aaa");
        File[] files = file.listFiles();          // 获取D盘aaa目录下的所有内容 
        System.out.println(files.length);
        for (File path : files) {
            System.out.println(path);
        }
    }
}

综合练习

项目代码结构

本次博客示例的项目结构如下:

filemodule/
└── src/
    └── com/
        └── wb/
            ├── filedemo/
            │   ├── FileDemo1.java 
            │   ├── FileDemo2.java 
            │   ├── FileDemo3.java 
            │   ├── FileDemo4.java 
            │   ├── FileDemo5.java 
            │   └── FileDemo6.java 
            └── filetest/
                ├── Test1.java 
                ├── Test2.java 
                └── Test3.java 

filedemo 包:演示 File 类基本 API 的用法。
filetest 包:综合练习,运用所学知识解决实际问题。

1 ) 练习1:在指定目录中创建文件

需求:在当前模块的 aaa 文件夹下创建一个 a.txt 文件。

关键点:createNewFile 要求父文件夹必须存在,否则会抛出 IOException
因此需要先判断并创建目录,再创建文件。

// Test1.java 
public class Test1 {
    public static void main(String[] args) throws IOException {
        // 目标:在 module/aaa/ 下创建 a.txt 
        File file = new File("filemodule\\aaa");
        if (!file.exists()) {
            // 若aaa文件夹不存在,先创建(mkdirs保证多级创建)
            file.mkdirs();
        }
        // 拼接新文件路径 
        File newFile = new File(file, "a.txt");
        newFile.createNewFile();
    }
}

2 ) 练习2:递归删除多级文件夹

需求:删除一个包含子文件和子文件夹的多级文件夹。

思路:

  1. 进入文件夹,获取所有内部内容的File对象数组。
  2. 遍历数组:如果是文件则直接删除;如果是文件夹则递归删除。
  3. 内部清空后,最后删除自身。

递归流程图(假设目录结构为 src 内含 a.txt、b.txt 和 AAA 文件夹,AAA 内含 a.txt 和空文件夹):

是文件

是文件夹 (AAA)

a.txt

空文件夹

调用 deleteDir(src)

listFiles 获取 src 内容

遍历数组

直接 delete

递归调用 deleteDir(AAA)

listFiles 获取 AAA 内容

遍历

delete

递归 deleteDir(空文件夹)

listFiles 返回空数组, 遍历跳过

delete 空文件夹

delete AAA

delete src

对应代码:

// Test2.java 
public class Test2 {
    public static void main(String[] args) {
        File src = new File("C:\\Users\\apple\\Desktop\\src");
        deleteDir(src);
    }
 
    private static void deleteDir(File src) {
        // 1. 进入文件夹,获取所有内容 
        File[] files = src.listFiles();
        // 2. 遍历 
        for (File file : files) {
            if (file.isFile()) {
                // 3. 文件直接删除 
                file.delete();
            } else {
                // 4. 文件夹:递归删除 
                deleteDir(file);
            }
        }
        // 最后删除该文件夹自身 
        src.delete();
    }
}

3 ) 练习3:统计文件夹中每种文件出现的次数

需求:统计一个文件夹中,每种文件(.txt, .java, .jpg 等)的数量并打印。

思路:
使用 HashMap<String, Integer> 集合,键为后缀名,值为次数。
利用递归遍历所有子文件夹。
对于每个文件,截取后缀名,更新Map中的计数。

注意:需处理无后缀或特殊文件名的情况,此处仅统计正则分割后长度为2的文件。

// Test3.java 
public class Test3 {
    public static void main(String[] args) {
        File file = new File("filemodule");
        HashMap<String, Integer> hm = new HashMap<>();
        getCount(hm, file);
        System.out.println(hm);
    }
 
    private static void getCount(HashMap<String, Integer> hm, File file) {
        File[] files = file.listFiles();
        for (File f : files) {
            if (f.isFile()) {
                String fileName = f.getName();
                String[] fileNameArr = fileName.split("\\.");
                if (fileNameArr.length == 2) {
                    String fileEndName = fileNameArr[1];
                    if (hm.containsKey(fileEndName)) {
                        // 已存在:获取原有次数,+1 
                        Integer count = hm.get(fileEndName);
                        count++;
                        hm.put(fileEndName, count);
                    } else {
                        // 首次出现:次数记为1 
                        hm.put(fileEndName, 1);
                    }
                }
            } else {
                // 文件夹:递归 
                getCount(hm, f);
            }
        }
    }
}

这样,我们便完成了对文件夹内各类文件数量的统计。

总结

通过本篇的学习,你将掌握 File 类的基本使用方法,理解绝对/相对路径、文件的创建与删除、递归操作等核心技能,为后续学习 IO 流打下坚实基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值