📁1. File 类
#
什么是 File 类
#
File 类是 Java 提供的用于操作文件和目录的类,位于 java.io 包中。它代表文件或目录的路径名抽象表示,但不代表文件的实际内容。
重要提示:File 类只能操作文件或目录本身(创建、删除、重命名等),不能读写文件内容。要读写文件内容需要使用 IO 流。
核心作用
#
| 功能类别 |
具体作用 |
| 文件/目录信息获取 |
获取名称、路径、大小、修改时间等 |
| 文件/目录操作 |
创建、删除、重命名文件或目录 |
| 判断功能 |
判断是否存在、是否为文件/目录、是否可读写 |
| 目录遍历 |
列出目录下的文件和子目录 |
3个常用构造方法
#
// 1. 根据路径字符串创建
File file1 = new File("D:\\test.txt");
// 2. 根据父路径和子路径创建
File file2 = new File("D:\\", "test.txt");
// 3. 根据父 File 对象和子路径创建
File parent = new File("D:\\");
File file3 = new File(parent, "test.txt");
常用方法一览
#
判断方法
#
| 方法 |
说明 |
boolean exists() |
判断文件或目录是否存在 |
boolean isFile() |
判断是否为文件 |
boolean isDirectory() |
判断是否为目录 |
boolean canRead() |
判断是否可读 |
boolean canWrite() |
判断是否可写 |
获取方法
#
| 方法 |
说明 |
String getName() |
获取文件或目录名称 |
String getPath() |
获取路径字符串 |
String getAbsolutePath() |
获取绝对路径 |
long length() |
获取文件大小**(字节)** |
long lastModified() |
获取最后修改时间(时间戳) |
创建和删除方法
#
| 方法 |
说明 |
boolean createNewFile() |
创建新文件(文件不存在时) |
boolean mkdir() |
创建单级目录 |
boolean mkdirs() |
创建多级目录 |
boolean delete() |
删除文件或空目录 |
遍历方法
#
| 方法 |
说明 |
String[] list() |
获取目录下所有文件和目录的名称数组(一级) |
File[] listFiles() |
获取目录下所有文件和目录的 File 对象数组(一级) |
使用实例
#
import [java.io](http://java.io).File;
import [java.io](http://java.io).IOException;
import java.text.SimpleDateFormat;
import [java.util.Date](http://java.util.Date);
public class FileDemo {
public static void main(String[] args) throws IOException {
// 1. 创建 File 对象
File file = new File("D:\\demo\\test.txt");
// 2. 创建文件(需要先创建父目录)
File parentDir = file.getParentFile();
if (!parentDir.exists()) {
parentDir.mkdirs(); // 创建多级目录
}
if (!file.exists()) {
file.createNewFile(); // 创建文件
System.out.println("文件创建成功");
}
// 3. 获取文件信息
System.out.println("文件名:" + file.getName());
System.out.println("绝对路径:" + file.getAbsolutePath());
System.out.println("文件大小:" + file.length() + " 字节");
// 格式化时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("最后修改时间:" + sdf.format(new Date(file.lastModified())));
// 4. 判断
System.out.println("是否为文件:" + file.isFile());
System.out.println("是否可读:" + file.canRead());
// 5. 遍历目录
File dir = new File("D:\\demo");
File[] files = dir.listFiles();
if (files != null) {
for (File f : files) {
System.out.println((f.isDirectory() ? "[目录] " : "[文件] ") + f.getName());
}
}
}
}
🌊2. IO 流体系
#
什么是 IO 流
#
IO 流(Input/Output Stream) 是 Java 用于处理输入输出操作的机制,可以实现数据在程序与外部设备(文件、网络、内存等)之间的传输。
形象理解:把数据想象成水,IO 流就是水管,负责将数据从源头(输入)流向目的地(输出)。
IO 流的分类
#
按流向分类
#
| 类型 |
说明 |
代表类 |
| 输入流(Input) |
将数据从外部读入程序 |
InputStream、Reader |
| 输出流(Output) |
将数据从程序写出到外部 |
OutputStream、Writer |
按数据类型分类
#
| 类型 |
说明 |
单位 |
代表类 |
| 字节流 |
处理二进制数据(图片、视频、音频等) |
字节(byte) |
InputStream、OutputStream |
| 字符流 |
处理文本数据(自动处理编码) |
字符(char) |
Reader、Writer |
IO 流体系结构
#
📖3. 字节流详解
#
FileInputStream(文件字节输入流)
#
核心方法
#
| 方法 |
说明 |
缺点 |
int read() |
读取一个字节,返回字节值(0-255),到末尾返回 -1 |
每次读一个字节效率低 |
int read(byte[] b) |
读取多个字节到数组,返回实际读取的字节数 |
还是无法解决读汉字乱码问题 |
void close() |
关闭流,释放资源 |
|
使用实例
#
import [java.io](http://java.io).FileInputStream;
import [java.io](http://java.io).IOException;
public class FileInputStreamDemo {
public static void main(String[] args) {
// 方式一:单字节读取(效率低,不推荐)
try (FileInputStream fis = new FileInputStream("D:\\test.txt")) {
int data;
while ((data = [fis.read](http://fis.read)()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
// 方式二:字节数组读取(推荐)
try (FileInputStream fis = new FileInputStream("D:\\test.txt")) {
byte[] buffer = new byte[1024]; // 缓冲区
int len;
while ((len = [fis.read](http://fis.read)(buffer)) != -1) {
System.out.print(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileOutputStream(文件字节输出流)
#
核心方法
#
| 方法 |
说明 |
void write(int b) |
写入一个字节 |
void write(byte[] b) |
写入字节数组 |
void write(byte[] b, int off, int len) |
写入字节数组的一部分 |
void close() |
关闭流并刷新缓冲区 |
使用实例
#
import [java.io](http://java.io).FileOutputStream;
import [java.io](http://java.io).IOException;
public class FileOutputStreamDemo {
public static void main(String[] args) {
// 创建输出流(第二个参数 true 表示追加模式)
try (FileOutputStream fos = new FileOutputStream("D:\\output.txt", true)) {
// 方式一:写入单个字节
fos.write(65); // 写入字符 'A'
// 方式二:写入字节数组
String text = "Hello, Java IO!";
fos.write(text.getBytes());
// 写入换行符
fos.write("\r\n".getBytes());
System.out.println("写入成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
文件复制实战
#
import [java.io](http://java.io).*;
public class FileCopyDemo {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
try (FileInputStream fis = new FileInputStream("D:\\[source.mp](http://source.mp)4");
FileOutputStream fos = new FileOutputStream("D:\\[target.mp](http://target.mp)4")) {
byte[] buffer = new byte[8192]; // 8KB 缓冲区
int len;
while ((len = [fis.read](http://fis.read)(buffer)) != -1) {
fos.write(buffer, 0, len);
}
long endTime = System.currentTimeMillis();
System.out.println("复制完成,耗时:" + (endTime - startTime) + " 毫秒");
} catch (IOException e) {
e.printStackTrace();
}
}
}
📝4. 字符流详解
#
FileReader(文件字符输入流)
#
使用实例
#
import [java.io](http://java.io).FileReader;
import [java.io](http://java.io).IOException;
public class FileReaderDemo {
public static void main(String[] args) {
try (FileReader fr = new FileReader("D:\\test.txt")) {
char[] buffer = new char[1024];
int len;
while ((len = [fr.read](http://fr.read)(buffer)) != -1) {
System.out.print(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileWriter(文件字符输出流)
#
核心方法
#
| 方法 |
说明 |
void write(int c) |
写入单个字符 |
void write(char[] cbuf) |
写入字符数组 |
void write(String str) |
写入字符串 |
void flush() |
刷新缓冲区 |
void close() |
关闭流(自动刷新) |
使用实例
#
import [java.io](http://java.io).FileWriter;
import [java.io](http://java.io).IOException;
public class FileWriterDemo {
public static void main(String[] args) {
try (FileWriter fw = new FileWriter("D:\\output.txt")) {
// 写入字符串
fw.write("第一行文本\r\n");
fw.write("第二行文本\r\n");
// 写入字符数组
char[] chars = {'J', 'a', 'v', 'a'};
fw.write(chars);
fw.flush(); // 刷新到磁盘
System.out.println("写入成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
⚡5. 缓冲流(高效流)
#
为什么需要缓冲流
#
普通流每次读写都直接操作磁盘,效率较低。缓冲流内部维护一个缓冲区(默认 8KB)对之前的流进行改装,减少实际的磁盘访问次数,大幅提升性能。
BufferedInputStream & BufferedOutputStream
#
使用实例
#
import [java.io](http://java.io).*;
public class BufferedStreamDemo {
public static void main(String[] args) {
// 使用缓冲流复制文件
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("D:\\[source.zip](http://source.zip)"));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("D:\\[target.zip](http://target.zip)"))) {
byte[] buffer = new byte[1024];
int len;
while ((len = [bis.read](http://bis.read)(buffer)) != -1) {
bos.write(buffer, 0, len);
}
System.out.println("复制完成");
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedReader & BufferedWriter
#
特有方法
#
| 方法 |
说明 |
String readLine() |
读取一行文本(不包含换行符) |
void newLine() |
写入系统相关的换行符 |
使用实例
#
import [java.io](http://java.io).*;
public class BufferedReaderWriterDemo {
public static void main(String[] args) {
// 按行读取文件
try (BufferedReader br = new BufferedReader(
new FileReader("D:\\input.txt"));
BufferedWriter bw = new BufferedWriter(
new FileWriter("D:\\output.txt"))) {
String line;
int lineNumber = 1;
while ((line = br.readLine()) != null) {
// 在每行前添加行号
bw.write(lineNumber + ": " + line);
bw.newLine(); // 写入换行符
lineNumber++;
}
System.out.println("处理完成");
} catch (IOException e) {
e.printStackTrace();
}
}
}
🔄6. 转换流
#
作用
#
转换流是字节流与字符流之间的桥梁,可以指定字符编码。
| 类名 |
作用 |
| InputStreamReader |
将字节输入流转换为字符输入流(解码) |
| OutputStreamWriter |
将字符输出流转换为字节输出流(编码) |
使用场景
#
- 处理不同编码的文本文件(UTF-8、GBK 等)
- 从网络、控制台等字节流中读取字符数据
使用实例
#
import [java.io](http://java.io).*;
public class ConvertStreamDemo {
public static void main(String[] args) {
// 读取 GBK 编码的文件
try (InputStreamReader isr = new InputStreamReader(
new FileInputStream("D:\\gbk.txt"), "GBK");
BufferedReader br = new BufferedReader(isr)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
// 写入 UTF-8 编码的文件
try (OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("D:\\utf8.txt"), "UTF-8");
BufferedWriter bw = new BufferedWriter(osw)) {
bw.write("这是 UTF-8 编码的文本");
bw.newLine();
} catch (IOException e) {
e.printStackTrace();
}
}
}
📦7. 对象流(序列化)
#
什么是序列化
#
| 概念 |
说明 |
| 序列化 |
将对象转换为字节序列,保存到文件或网络传输 |
| 反序列化 |
将字节序列还原为对象 |
使用条件
#
对象的类必须实现 Serializable 接口(标记接口,无需实现方法)
import [java.io](http://java.io).Serializable;
public class Student implements Serializable {
private static final long serialVersionUID = 1L; // 版本号
private String name;
private int age;
private transient String password; // transient 修饰的字段不会被序列化
// 构造方法、getter、setter 省略
}
使用实例
#
import [java.io](http://java.io).*;
public class ObjectStreamDemo {
public static void main(String[] args) {
// 序列化:将对象写入文件
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("D:\\student.dat"))) {
Student student = new Student("张三", 20, "123456");
oos.writeObject(student);
System.out.println("序列化成功");
} catch (IOException e) {
e.printStackTrace();
}
// 反序列化:从文件读取对象
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("D:\\student.dat"))) {
Student student = (Student) ois.readObject();
System.out.println("反序列化成功:" + student);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
📋8. IO 流选择指南
#
常见组合方案
#
| 场景 |
推荐方案 |
| 读取文本文件 |
FileReader + BufferedReader |
| 写入文本文件 |
FileWriter + BufferedWriter |
| 复制二进制文件 |
FileInputStream + BufferedInputStream |
- FileOutputStream + BufferedOutputStream |
| 读取指定编码文本 | FileInputStream + InputStreamReader + BufferedReader |
| 对象持久化 | FileOutputStream + ObjectOutputStream |
💡9. 最佳实践
#
1. 使用 try-with-resources 自动关闭流
#
// 推荐写法:自动关闭资源
try (FileInputStream fis = new FileInputStream("test.txt")) {
// 使用流
} catch (IOException e) {
e.printStackTrace();
}
2. 优先使用缓冲流
#
// 普通流
FileReader fr = new FileReader("test.txt");
// 缓冲流(性能更好)
BufferedReader br = new BufferedReader(new FileReader("test.txt"));
3. 合理设置缓冲区大小
#
// 小文件:1KB - 4KB
byte[] buffer = new byte[1024];
// 大文件:8KB - 64KB
byte[] buffer = new byte[8192];
4. 处理异常要具体
#
try {
// IO 操作
} catch (FileNotFoundException e) {
System.out.println("文件不存在");
} catch (IOException e) {
System.out.println("读写错误");
}
10. IO框架
#
commons-io框架包
- FileUtils类
- IOUtils类
🧰 Apache Commons IO 简介
#
Apache Commons IO 是 Apache 提供的 IO 工具库,封装了文件与流的常见操作,减少样板代码、提升可读性与安全性。常用组件包括 FileUtils、IOUtils、FilenameUtils、FileFilterUtils、EndianUtils 等。
依赖引入
#
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.1</version>
</dependency>
dependencies {
implementation 'commons-io:commons-io:2.15.1'
}
选择与 JDK 版本兼容的最新稳定版即可,2.11+ 对 JDK8 友好,2.15+ 适配更高版本。
📂 FileUtils 常用功能
#
FileUtils 主要用于“文件与目录”的便捷操作。
1) 读写文件
#
// 读字符串(按编码)
String content = FileUtils.readFileToString(new File("a.txt"), StandardCharsets.UTF_8);
// 写字符串(覆盖或追加)
FileUtils.writeStringToFile(new File("b.txt"), "你好,Commons IO\n", StandardCharsets.UTF_8, true);
// 读写字节数组
byte[] bytes = FileUtils.readFileToByteArray(new File("pic.png"));
FileUtils.writeByteArrayToFile(new File("copy.png"), bytes);
2) 文件复制、移动、删除
#
// 复制文件或目录
FileUtils.copyFile(new File("a.txt"), new File("dest/a.txt"));
FileUtils.copyDirectory(new File("srcDir"), new File("destDir"));
// 移动(含覆盖目录处理)
FileUtils.moveFile(new File("a.txt"), new File("moved/a.txt"));
FileUtils.moveDirectory(new File("srcDir"), new File("movedDir"));
// 删除(安静删除,不抛异常)
FileUtils.deleteQuietly(new File("temp.log"));
// 强制删除目录
FileUtils.deleteDirectory(new File("outDir"));
3) 遍历与过滤
#
// 列出目录下满足扩展名的文件(递归)
Collection<File> files = FileUtils.listFiles(
new File("project"), new String[]{"java", "md"}, true);
// 遍历文件并处理大小、修改时间
for (File f : files) {
long size = FileUtils.sizeOf(f); // 文件大小
long dirSize = FileUtils.sizeOfDirectory(f.getParentFile());
}
4) 临时文件与磁盘空间
#
// 创建父目录
FileUtils.forceMkdir(new File("logs/app"));
// 可用空间查询(字节)
long free = FileUtils.freeSpaceKb("C:");
小贴士:对于大文件复制,配合 NIO 或 Buffered 流可能更高效;FileUtils 胜在简洁可靠。
🔗 IOUtils 常用功能
#
IOUtils 主要用于“流”的读写、拷贝和关闭等操作。
1) 流与字符串、字节的互转
#
// InputStream -> String / byte[]
String text = IOUtils.toString(new FileInputStream("a.txt"), StandardCharsets.UTF_8);
byte[] data = IOUtils.toByteArray(new FileInputStream("pic.jpg"));
// String / byte[] -> OutputStream
IOUtils.write("hello", new FileOutputStream("b.txt"), StandardCharsets.UTF_8);
IOUtils.write(data, new FileOutputStream("copy.jpg"));
2) 流拷贝与按行读取
#
// 高效复制(内部有缓冲)
try (InputStream in = new FileInputStream("large.bin");
OutputStream out = new FileOutputStream("large.copy.bin")) {
long n = IOUtils.copy(in, out); // 返回复制的字节数
}
// 按行读取
try (InputStream in = new FileInputStream("log.txt");
Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8)) {
List<String> lines = IOUtils.readLines(reader);
lines.forEach(System.out::println);
}
3) 安静关闭与 NOP 输出
#
// 安静关闭(吞异常,谨慎使用)
Closeable c = new FileInputStream("a.txt");
IOUtils.closeQuietly(c);
// 一个丢弃所有数据的 OutputStream(调试场景)
OutputStream blackhole = IOUtils.nullOutputStream();
🆚 FileUtils vs IOUtils 该用谁?
#
- 处理“文件/目录” → 选 FileUtils
- 处理“流”读写、转换、复制 → 选 IOUtils
- 复制文件:已知是文件对象 → FileUtils.copyFile。若你只有 InputStream → IOUtils.copy
✅ 实战示例:按行过滤复制文本
#
public static void filterCopy(Path src, Path dest) throws IOException {
try (BufferedReader br = Files.newBufferedReader(src, StandardCharsets.UTF_8);
Writer writer = new OutputStreamWriter(new FileOutputStream(dest.toFile()), StandardCharsets.UTF_8)) {
for (String line; (line = br.readLine()) != null; ) {
if (!line.isBlank()) {
IOUtils.write(line + System.lineSeparator(), writer);
}
}
}
}
✅ 实战示例:目录递归复制并统计大小
#
public static long copyAndSize(File srcDir, File destDir) throws IOException {
FileUtils.copyDirectory(srcDir, destDir);
return FileUtils.sizeOfDirectory(destDir);
}