一篇文章教你学会用 Java 程序操作文件
文件操作是 Java 开发中最常见、最基础但也最容易出错的操作之一。
从最基础的读写,到路径处理、字符编码、异常处理、大文件流式读取,再到现代 Java 的新特性,本文尽量用清晰、实用的方式带你把 Java 文件操作“一次搞懂”。
一、Java 文件操作核心类对比(2025 年视角)
| 场景需求 | 推荐类/方式 | 是否推荐 | 说明与适用场景 |
|---|---|---|---|
| 读写字节流(图片、视频等) | FileInputStream / FileOutputStream | 基础 | 最原始方式,现已较少直接使用 |
| 带缓冲的字节流 | BufferedInputStream / BufferedOutputStream | 推荐 | 性能更好,几乎是字节流的标配 |
| 读写字符流(文本文件) | FileReader / FileWriter | 不推荐 | 编码问题多,容易乱码 |
| 带缓冲的字符流 | BufferedReader / BufferedWriter | 强烈推荐 | 文本文件首选,性能好、API 友好 |
| 更现代、简洁的方式 | Files(java.nio.file) | ★★★★★ | Java 7+ 强烈推荐,几乎覆盖所有常见场景 |
| 大文件 / 流式处理 | Files.newBufferedReader() / Files.lines() | 推荐 | 内存友好,适合超大文件 |
| 路径处理 | Path + Paths | 必须掌握 | 跨平台、规范化路径的最佳方式 |
结论:现代 Java 项目中 80% 以上的文件操作都可以用 java.nio.file.Files 搞定。
二、必须掌握的核心类与接口
java.io.File:老派文件抽象(路径、创建、删除、判断存在等)java.nio.file.Path/Paths:现代路径表示(不可变、链式)java.nio.file.Files:静态工具类,几乎所有操作都在这里java.nio.charset.StandardCharsets:常用编码常量(UTF-8、UTF-16 等)
三、常用操作完整代码示例
1. 判断文件/目录是否存在、创建
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;
public class FileBasic {
public static void main(String[] args) throws IOException {
Path path = Paths.get("data", "test.txt");
// 是否存在
boolean exists = Files.exists(path);
System.out.println("文件是否存在:" + exists);
// 创建目录(多级目录用 createDirectories)
Files.createDirectories(path.getParent());
// 创建文件(如果不存在则创建,已存在不报错)
if (!Files.exists(path)) {
Files.createFile(path);
System.out.println("文件创建成功");
}
}
}
2. 写文件(最推荐的几种方式)
// 方式1:一次性写入字符串(适合小文件)
Files.writeString(
Paths.get("output.txt"),
"你好,Java 文件操作\n这是第二行",
StandardCharsets.UTF_8
);
// 方式2:追加写入
Files.writeString(
Paths.get("output.txt"),
"追加内容\n",
StandardCharsets.UTF_8,
StandardOpenOption.APPEND
);
// 方式3:写入字节数组
byte[] bytes = "二进制内容".getBytes(StandardCharsets.UTF_8);
Files.write(Paths.get("data.bin"), bytes);
// 方式4:使用 BufferedWriter(适合大文本、需要逐行写)
try (BufferedWriter writer = Files.newBufferedWriter(
Paths.get("log.txt"),
StandardCharsets.UTF_8,
StandardOpenOption.CREATE, StandardOpenOption.APPEND)) {
writer.write("时间:" + LocalDateTime.now());
writer.newLine();
writer.write("消息:操作成功");
}
3. 读文件(最常用几种方式)
// 方式1:一次性读取全部内容为字符串(小文件)
String content = Files.readString(Paths.get("input.txt"), StandardCharsets.UTF_8);
System.out.println(content);
// 方式2:读取所有行(List<String>)
List<String> lines = Files.readAllLines(Paths.get("config.txt"));
lines.forEach(System.out::println);
// 方式3:流式读取(超大文件推荐,内存友好)
try (Stream<String> stream = Files.lines(Paths.get("bigfile.log"))) {
stream
.filter(line -> line.contains("ERROR"))
.limit(100)
.forEach(System.out::println);
} catch (IOException e) {
// 处理异常
}
// 方式4:传统 BufferedReader(老项目常见)
try (BufferedReader reader = Files.newBufferedReader(Paths.get("data.csv"))) {
String line;
while ((line = reader.readLine()) != null) {
// 处理每一行
System.out.println(line);
}
}
4. 复制、移动、删除文件/目录
Path source = Paths.get("source.txt");
Path target = Paths.get("backup", "source_backup.txt");
// 复制(可覆盖)
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
// 移动(相当于剪切)
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
// 删除单个文件
Files.deleteIfExists(Paths.get("temp.txt"));
// 删除目录(需目录为空)
Files.delete(Paths.get("empty_dir"));
// 递归删除目录(需自己实现或用第三方库)
5. 遍历文件夹(列出所有文件)
// 方法1:列出当前目录文件
Files.list(Paths.get("photos"))
.forEach(System.out::println);
// 方法2:递归遍历(查找所有 .jpg)
try (Stream<Path> walk = Files.walk(Paths.get("project"))) {
walk.filter(Files::isRegularFile)
.filter(p -> p.toString().toLowerCase().endsWith(".jpg"))
.forEach(p -> System.out.println("找到图片:" + p));
}
四、常见问题与最佳实践
| 问题 | 推荐做法 | 说明 |
|---|---|---|
| 中文文件名乱码 | 始终显式使用 StandardCharsets.UTF_8 | 避免平台默认编码差异 |
| 超大文件内存溢出 | 使用 Files.lines() 或 newBufferedReader() | 流式读取,不一次性加载 |
| 忘记关闭流导致句柄泄漏 | 永远使用 try-with-resources | 自动关闭 |
| 跨平台路径分隔符问题 | 永远使用 Path / Paths.get() 而不是字符串拼接 | 自动处理 / 和 \ |
| 想同时读写同一个文件 | 使用 RandomAccessFile 或分段读写 | 慎用 |
| 需要监视文件变化 | 使用 WatchService(NIO.2) | 实现热加载、日志监控 |
五、现代 Java(17+ / 21+)推荐写法小结
// 读文件最简洁方式
String content = Files.readString(Path.of("config.yml"));
// 写文件最简洁方式
Files.writeString(Path.of("log.txt"), "启动成功", StandardOpenOption.APPEND);
// 安全创建目录并写文件
Path dir = Path.of("logs", LocalDate.now().toString());
Files.createDirectories(dir);
Files.writeString(dir.resolve("app.log"), "记录一条日志\n", StandardOpenOption.APPEND, StandardOpenOption.CREATE);
六、总结口诀
小文件读写用
Files.readString/writeString
大文件一定要Files.lines()或newBufferedReader
路径处理一律用Path+Paths.get()
编码永远写死UTF-8
所有 IO 操作必须try-with-resources
目录操作别忘记createDirectories
希望这篇内容能让你对 Java 文件操作从“会用”到“用得舒服”有一个质的提升。
如果你还有具体场景想深入(比如大文件分片上传、文件指纹计算、NIO.2 WatchService 实战、Files 的异常处理细节等),随时告诉我,继续深入!