1. File 类
1.1 File 类概述
File类是 Java IO 体系中用于表示文件或目录路径的核心类。
主要功能包括:
- 创建、删除文件 / 目录
- 判断文件 / 目录是否存在
- 获取文件 / 目录的路径、名称、大小等信息
- 注意:
File类不能读写文件内容,仅处理路径相关操作
1.2 相对路径和绝对路径
- 绝对路径 :包含盘符(Windows)或根目录(Linux/Mac)的完整路径,例如:
- Windows:
E:/io/java.txt - Linux/Mac:
/home/user/io/java.txt
- Windows:
- 相对路径 :相对于当前项目根目录的路径,无需写盘符,例如:
io/file(等价于项目根目录下的io/file文件夹)
1.3 构造方法案例
java
运行
import java.io.File;
import java.io.IOException;
public class FileTest {
public static void main(String[] args) throws IOException {
System.out.println("----------------File类的构造方法-------------------");
// 1. 直接传入绝对路径
File f1 = new File("E:/io/java.txt");
System.out.println(f1.getAbsolutePath());// 输出:E:\io\java.txt
// 2. 传入相对路径
File f2 = new File("io/file");
System.out.println(f2.getAbsolutePath());// 输出:项目根目录\io\file
// 3. 父路径(字符串)+ 子路径(字符串)
File f3 = new File("E:/io", "java.txt");
System.out.println(f3.getAbsolutePath());// 输出:E:\io\java.txt
// 4. 父路径(File对象)+ 子路径(字符串)
File f4 = new File(new File("E:/IO"), "java.txt");
System.out.println(f4.getAbsolutePath());// 输出:E:\IO\java.txt
}
}
1.4 创建功能
File类提供mkdir()(创建单级目录)、mkdirs()(创建多级目录)、createNewFile()(创建文件)方法,代码如下:
java
import java.io.File;
import java.io.IOException;
public class FileMethodTest1 {
public static void main(String[] args) throws IOException {
System.out.println("-----------创建多级目录----------------");
File file = new File("io/myFile");
// System.out.println(file.mkdir());// 只能创建单级目录,若父目录不存在则失败
System.out.println(file.mkdirs());// 创建多级目录,父目录不存在则自动创建(推荐)
System.out.println("-----------创建文件---------");
File file1 = new File("io/myFile/java.txt");
System.out.println(file1.createNewFile());// 若文件不存在则创建,返回true;否则返回false
}
}
1.5 判断和获取功能
常用判断方法(isDirectory()、isFile()、exists())和获取方法(getAbsolutePath()、getName()等)实战:
java
import java.io.File;
public class FileMethodTest2 {
public static void main(String[] args) {
File file = new File("io/myFile/java.txt");
System.out.println("------------判断功能-------------");
System.out.println(file.isDirectory());// 判断是否为目录:false
System.out.println(file.isFile());// 判断是否为文件:true
System.out.println(file.exists());// 判断是否存在:true
System.out.println("------------获取功能-------------");
System.out.println(file.getAbsolutePath());// 获取绝对路径
System.out.println(file.getPath());// 获取构造方法中传入的路径
System.out.println(file.getName());// 获取文件/目录名:java.txt
System.out.println(file.length());// 获取文件大小(字节数)
System.out.println("------------获取当前目录下的文件、目录的名字-------------");
String[] strArr = new File("D:/").list();// 获取目录下所有文件/目录的名称数组
for (String str : strArr) {
System.out.println(str);
}
System.out.println("------------获取当前目录下的文件、目录的File[]-------------");
File[] fileArr = new File("D:/").listFiles();// 获取目录下所有文件/目录的File对象数组
for (File f : fileArr) {
if(f.isFile()){
System.out.println(f.getAbsolutePath()+"--->"+f.length());// 文件:输出路径+大小
}else{
System.out.println(f.getAbsolutePath());// 目录:仅输出路径
}
}
}
}
1.6 删除功能
delete()方法可删除文件或空目录(非空目录需先删除子内容):
import java.io.File;
import java.io.IOException;
public class FileMethodTest3 {
public static void main(String[] args) throws IOException {
System.out.println("----------删除文件---------------");
File file = new File("io/test.txt");
file.createNewFile();// 先创建文件
System.out.println(file.delete());// 删除文件:true
System.out.println("----------删除目录---------------");
File file1 = new File("io/dir");
file1.mkdirs();// 先创建空目录
System.out.println(file1.delete());// 删除空目录:true
}
}
1.7 练习
练习 1:查找指定目录下后缀为.jpg 的文件
import java.io.File;
public class JpgFileSearch {
public static void main(String[] args) {
File dir = new File("D:/");// 指定目录
searchJpgFiles(dir);
}
public static void searchJpgFiles(File dir) {
if (dir.exists() && dir.isDirectory()) {
File[] fileArr = dir.listFiles();
if (fileArr != null) {
for (File file : fileArr) {
if (file.isFile() && file.getName().endsWith(".jpg")) {
System.out.println("找到.jpg文件:" + file.getAbsolutePath());
} else if (file.isDirectory()) {
searchJpgFiles(file);// 递归查找子目录
}
}
}
} else {
System.out.println("目录不存在或不是目录");
}
}
}
练习 2:递归遍历目录下所有文件(输出绝对路径)
import java.io.File;
import java.io.IOException;
public class FileTraversalTest {
public static void main(String[] args) throws IOException {
File srcFile = new File("D:/");
getAllFilePath(srcFile);
}
// 递归遍历目录,输出所有文件的绝对路径
public static void getAllFilePath(File srcFile) {
File[] fileArray = srcFile.listFiles();
if (fileArray != null) {
for (File file : fileArray) {
if (file.isDirectory()) {
getAllFilePath(file);// 目录:递归调用
} else {
System.out.println(file.getAbsolutePath());// 文件:输出绝对路径
}
}
}
}
}
2. IO 流概述
2.1 什么是 IO 流?
- IO 流(Input/Output Stream):用于程序与外部设备(文件、网络、键盘等)之间的数据传输
- 核心作用:读(Input):从外部设备获取数据到程序;写(Output):从程序输出数据到外部设备
- 注意:输入 / 输出是相对于程序而言的(例:读取文件→输入流;写入文件→输出流)
2.2 IO 流的分类
IO 流主要分为两大派系,再按数据单位细分:

| 分类维度 | 具体类型 | 核心类(字节流) | 核心类(字符流) |
|---|---|---|---|
| 数据单位 | 字节流(8 位) | InputStream/OutputStream | - |
| 字符流(16 位,char) | - | Reader/Writer | |
| 流向(相对程序) | 输入流 | FileInputStream | FileReader |
| 输出流 | FileOutputStream | FileWriter |
- 字节流:处理所有类型数据(图片、音频、视频、文本等),直接操作二进制
- 字符流:仅处理文本数据(.txt、.java 等),自动处理字符编码(UTF-8、GBK)
3. 字节流
字节流是 IO 流的基础,以字节为单位读写数据,适用于所有文件类型。
核心类:FileInputStream(读)、FileOutputStream(写)。
3.1 FileOutputStream(字节输出流)
用于向文件写入字节数据,构造方法支持 "覆盖写入" 和 "追加写入":
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamTest {
public static void main(String[] args) throws IOException {
/**
* 构造方法说明:
* 1. FileOutputStream(file):覆盖写入(文件存在则清空原有内容)
* 2. FileOutputStream(file, true):追加写入(文件存在则在末尾添加)
*/
File file = new File("fos.txt");
// 确保父目录存在
if(!file.exists()){
file.getParentFile().mkdirs();
file.createNewFile();
}
// 追加写入模式
FileOutputStream fos = new FileOutputStream("fos.txt", true);
// 写入数据(字符串需转字节数组)
for (int i = 0; i < 10; i++) {
fos.write("hello FileOutputStream".getBytes());// 写入字符串
fos.write("\n".getBytes());// 换行
}
fos.flush();// 刷新缓冲区(强制写入文件)
fos.close();// 关闭流(必须关闭,释放资源)
}
}
3.2 FileInputStream(字节输入流)
用于从文件读取字节数据,常用read()方法(返回单个字节,-1 表示读取结束):
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamTest {
public static void main(String[] args) {
FileInputStream fis = null;
try {
// 创建字节输入流,关联目标文件
fis = new FileInputStream("fos.txt");
int by;
// 循环读取:read()返回-1表示文件末尾
while ((by = fis.read()) != -1) {
// 字节转字符(适用于文本文件)
System.out.print((char) by);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 确保流关闭(finally块中执行)
try {
if (fis != null) fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4. 字符流
字符流是字节流的高层封装,以字符为单位读写,自动处理编码,适用于文本文件。
核心类:FileReader(读)、FileWriter(写)。
4.1 FileReader(字符输入流)
读取文本文件的字符数据,read()返回字符的 Unicode 码(-1 表示结束):
import java.io.FileReader;
import java.io.IOException;
public class FileReaderTest {
public static void main(String[] args) throws IOException {
// 关联文本文件
FileReader fr = new FileReader("abc.txt");
// 读取单个字符
int read = fr.read();// 返回Unicode码
System.out.println((char) read);// 转字符输出
System.out.println((char) fr.read());// 读取下一个字符
System.out.println(fr.read());// 无数据时返回-1
fr.close();// 关闭流
}
}
4.2 FileWriter(字符输出流)
向文本文件写入字符数据,支持直接写入字符串:
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterTest {
public static void main(String[] args) throws IOException {
// 关联文本文件(默认覆盖写入,追加模式:new FileWriter("abc.txt", true))
FileWriter fw = new FileWriter("abc.txt");
// 直接写入字符串(无需转字节)
fw.write("快乐、进取、奉献");
fw.flush();// 刷新缓冲区
fw.close();// 关闭流(关闭前会自动刷新)
}
}
5. 缓冲流
5.1 为什么使用缓冲流?
普通字节流 / 字符流每次读写都直接操作磁盘,效率低。
缓冲流在内存中创建缓冲区(字节数组 / 字符数组),先将数据缓存到内存,批量读写磁盘,大幅提升效率。
缓冲流是 "装饰器模式" 的应用,需依赖普通流(如FileInputStream)创建。
5.2 BufferedOutputStream(缓冲字节输出流)
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferedOutputStreamTest {
public static void main(String[] args) {
BufferedOutputStream bos = null;
try {
// 底层依赖FileOutputStream,缓冲区大小16字节(默认8192字节)
bos = new BufferedOutputStream(
new FileOutputStream("bos.txt"), 16);
String str = "hello BufferedOutputStream";
bos.write(str.getBytes());
// bos.flush();// 手动刷新(close()会自动刷新)
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭缓冲流(会自动关闭底层的FileOutputStream)
try {
if (bos != null) bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.3 BufferedInputStream(缓冲字节输入流)
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class BufferedInputStreamTest {
public static void main(String[] args) {
BufferedInputStream bis = null;
try {
// 底层依赖FileInputStream
bis = new BufferedInputStream(
new FileInputStream("bos.txt"), 16);
byte[] bys = new byte[1024];// 字节数组缓存
int len;
// 批量读取(每次读1024字节到bys数组)
while ((len = bis.read(bys)) != -1) {
System.out.print(new String(bys, 0, len));// 输出实际读取的字节
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bis != null) bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.4 BufferedReader(缓冲字符输入流)
新增readLine()方法,支持按行读取文本,效率极高:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderTest {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("abc.txt");
BufferedReader br = new BufferedReader(fr);
String result;
// 按行读取(返回null表示文件末尾)
while ((result = br.readLine()) != null) {
System.out.println(result);
}
// 关闭流原则:先开后关,后开先关
fr.close();
br.close();
}
}
5.5 BufferedWriter(缓冲字符输出流)
支持newLine()方法(跨平台换行),比\n更通用:
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWriterTest {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("abc.txt");
BufferedWriter bw = new BufferedWriter(fw);
bw.write("学历、能力、素养的三大优势");
bw.newLine();// 跨平台换行(Windows:\r\n,Linux:\n)
bw.write("缓冲流提升读写效率");
bw.flush();// 刷新缓冲区
// 关闭流(先关缓冲流,再关普通流)
bw.close();
fw.close();
}
}
6. 转换流
字符流默认使用系统编码,无法手动指定。
转换流是字节流与字符流的桥梁,支持自定义编码格式(如 UTF-8、GBK),解决中文乱码问题。
核心类:OutputStreamWriter(字节输出流→字符输出流)、InputStreamReader(字节输入流→字符输入流)。
6.1 OutputStreamWriter(字节转字符输出流)
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class OutputStreamWriterTest {
public static void main(String[] args) throws IOException {
// 1. 创建字节输出流
FileOutputStream fos = new FileOutputStream("abc.txt");
// 2. 转换为字符流,指定编码为GBK(需与读取时编码一致)
OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
// 3. 写入字符串(按指定编码转换为字节)
osw.write("文化启迪智慧,教育点亮人生");
System.out.println(osw.getEncoding());// 输出编码:GBK
// 4. 关闭流
osw.close();
fos.close();
}
}
6.2 InputStreamReader(字节转字符输入流)
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputStreamReaderTest {
public static void main(String[] args) throws IOException {
// 1. 创建字节输入流
FileInputStream fis = new FileInputStream("abc.txt");
// 2. 转换为字符流,指定编码为GBK(与写入时一致,避免乱码)
InputStreamReader isr = new InputStreamReader(fis, "GBK");
// 3. 读取数据
char[] chs = new char[1024];
int len;
while ((len = isr.read(chs)) != -1) {
System.out.print(new String(chs, 0, len));// 输出:文化启迪智慧,教育点亮人生
}
// 4. 关闭流
isr.close();
fis.close();
}
}
7. 对象流
7.1 概述
对象流用于对象的序列化与反序列化:
- 序列化:将 Java 对象转换为字节序列(可存储到文件、传输网络)
- 反序列化:将字节序列恢复为 Java 对象
核心类:ObjectOutputStream(序列化)、ObjectInputStream(反序列化)。
7.2 序列化(ObjectOutputStream)
注意 :对象要序列化,其所属类必须实现Serializable接口(标记接口,无抽象方法)。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
// 实现Serializable接口,支持序列化
class Student implements Serializable {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// getter/setter/toString省略
@Override
public String toString() {
return "Student{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
public class ObjectOutputStreamTest {
public static void main(String[] args) throws IOException {
// 1. 创建字节输出流
FileOutputStream fos = new FileOutputStream("io/myObjectStream/oos.txt");
// 2. 创建对象输出流(序列化流)
ObjectOutputStream oos = new ObjectOutputStream(fos);
// 3. 序列化对象(写入文件)
Student s = new Student("林青霞", 30);
oos.writeObject(s);
// 4. 关闭流
oos.close();
}
}
7.3 反序列化(ObjectInputStream)
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ObjectInputStreamTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 1. 创建字节输入流
FileInputStream fis = new FileInputStream("io/myObjectStream/oos.txt");
// 2. 创建对象输入流(反序列化流)
ObjectInputStream ois = new ObjectInputStream(fis);
// 3. 反序列化对象(读取字节序列→恢复对象)
Object obj = ois.readObject();
Student s = (Student) obj;
System.out.println(s);// 输出:Student{name='林青霞', age=30}
// 4. 关闭流
ois.close();
}
}
7.4 serialVersionUID(序列化版本号)
serialVersionUID是序列化 / 反序列化的版本标识符,用于确保反序列化时的类版本与序列化时一致:
- 自动生成:编译器根据类名、方法、字段自动计算(类结构变化时会改变)
- 手动指定(推荐):在类中添加
private static final long serialVersionUID = 1L;,类结构小改时仍可反序列化
7.5 transient(瞬时关键字)
若对象的某个成员变量无需序列化(如敏感数据、临时数据),用transient修饰:
class Student implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private transient int age; // age字段不序列化
// 其余代码不变
}
反序列化后,
transient字段会恢复为默认值(int→0,String→null)
练习:Account 对象序列化与反序列化
要求:Account 类(aid、accNo、accMoney)实现序列化,accMoney 为敏感数据无需序列化。
java
import java.io.*;
class Account implements Serializable {
private static final long serialVersionUID = 1L;
private int aid;
private String accNo;
private transient double accMoney; // 敏感数据,不序列化
public Account(int aid, String accNo, double accMoney) {
this.aid = aid;
this.accNo = accNo;
this.accMoney = accMoney;
}
@Override
public String toString() {
return "Account{" +
"aid=" + aid +
", accNo='" + accNo + '\'' +
", accMoney=" + accMoney +
'}';
}
}
public class AccountSerializeTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 序列化
FileOutputStream fos = new FileOutputStream("account.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(new Account(1, "622208XXXXXXXXXXXX", 10000.0));
oos.close();
// 反序列化
FileInputStream fis = new FileInputStream("account.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
Account account = (Account) ois.readObject();
System.out.println(account);
// 输出:Account{aid=1, accNo='622208XXXXXXXXXXXX', accMoney=0.0}(accMoney为默认值)
ois.close();
}
}
总结
Java IO 流的核心知识点与使用场景:
- File 类:处理文件 / 目录路径,无读写功能,是 IO 操作的基础。
- 字节流 :处理所有文件类型,
FileInputStream/FileOutputStream是基础。 - 字符流 :仅处理文本,自动编码,
FileReader/FileWriter简化文本操作。 - 缓冲流 :装饰普通流,提升效率,
BufferedReader的readLine()是文本读取首选。 - 转换流 :解决编码问题,
OutputStreamWriter/InputStreamReader支持自定义编码。 - 对象流 :实现对象序列化,需
Serializable接口,transient排除敏感字段。
使用建议:
- 文本文件:字符流 / 缓冲字符流(效率高、无乱码)
- 非文本文件(图片、视频):字节流 / 缓冲字节流
- 需指定编码:转换流
- 存储 / 传输对象:对象流
掌握以上内容,即可应对 Java 开发中绝大多数 IO 场景!如果有疑问,欢迎在评论区交流~