FileOutputStream:把数据写入磁盘
读是输入,写是输出。
FileOutputStream 把内存中的字节写入磁盘文件,就这么简单。但「怎么写」「写到哪里」「之前的内容怎么办」,这些问题决定了你的程序行为。
两种写入模式
java
// 覆盖模式(默认):文件存在则清空内容
FileOutputStream fos = new FileOutputStream("output.dat");
// 追加模式:文件存在则追加到末尾
FileOutputStream fos = new FileOutputStream("output.dat", true);覆盖 vs 追加的实战选择:
java
// 日志场景:追加模式,每次运行都记录
try (FileOutputStream fos = new FileOutputStream("app.log", true)) {
fos.write("New log entry\n".getBytes());
}
// 配置保存:覆盖模式,每次保存是最新的
try (FileOutputStream fos = new FileOutputStream("config.dat")) {
fos.write(configBytes);
}写入方式:与 FileInputStream 对称
单字节写入
java
try (FileOutputStream fos = new FileOutputStream("output.dat")) {
fos.write(65); // 写入字节 65(ASCII 'A')
fos.write("Hello".getBytes());
}不推荐:每次 write() 可能触发一次磁盘写入。
批量写入(推荐)
java
try (FileOutputStream fos = new FileOutputStream("output.dat")) {
byte[] data = "Hello World".getBytes();
fos.write(data); // 写整个数组
fos.write(data, 0, 5); // 写前 5 个字节
}带缓冲的批量写入(最佳)
java
try (
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("output.dat"), 8192)
) {
byte[] data = "Hello World".getBytes();
bos.write(data);
bos.flush(); // 强制写入磁盘
}
// BufferedOutputStream 在 close() 时自动 flush写文本文件:编码问题
这是最常见的坑。
java
// ❌ 错误:直接写字节,中文编码依赖系统
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
fos.write("你好".getBytes()); // 系统编码不确定,Linux 是 UTF-8,Windows 可能是 GBK
}
// ✅ 正确:用 OutputStreamWriter 指定 UTF-8
try (OutputStreamWriter writer = new OutputStreamWriter(
new FileOutputStream("output.txt"), StandardCharsets.UTF_8)) {
writer.write("你好");
}记住:写文本文件永远用 OutputStreamWriter,不要直接用 FileOutputStream。
写二进制数据:配合 DataOutputStream
如果需要写入 int、double 等基本类型:
java
try (
DataOutputStream dos = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("data.bin")))
) {
dos.writeInt(42);
dos.writeDouble(3.14159);
dos.writeBoolean(true);
}关于 DataOutputStream 的更多内容,参见数据流。
flush() vs close()
java
// flush():只刷新缓冲区,不关闭流
// close():先 flush,再关闭流
// BufferedOutputStream 需要 flush
try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("out.dat"))) {
bos.write("data".getBytes());
bos.flush(); // 立即写入磁盘,但不关闭
// 还可以继续写
}
// 普通 FileOutputStream 没有缓冲,flush() 没什么用
try (FileOutputStream fos = new FileOutputStream("out.dat")) {
fos.write("data".getBytes());
fos.flush(); // 等同于空操作
}避坑指南
目录不存在
java
// ❌ 目录不存在会抛异常
new FileOutputStream("/nonexistent/path/file.txt");
// ✅ 先创建父目录
File file = new File("/nonexistent/path/file.txt");
file.getParentFile().mkdirs(); // 创建所有不存在的父目录
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write("data".getBytes());
}忘记 close()
java
// ❌ 数据还在缓冲区,程序退出了,文件是空的
FileOutputStream fos = new FileOutputStream("out.dat");
fos.write("data".getBytes();
// 没有 close(),数据没写入磁盘
// ✅ 用 try-with-resources
try (FileOutputStream fos = new FileOutputStream("out.dat")) {
fos.write("data".getBytes());
}
// 自动 close,数据完整写入方法对照表
| 方法 | 说明 |
|---|---|
write(int b) | 写单字节(低 8 位) |
write(byte[] b) | 写整个数组 |
write(byte[] b, int off, int len) | 写数组区间 |
flush() | 强制刷新缓冲区到磁盘 |
close() | 关闭流(会自动 flush) |
写入口诀:覆盖还是追加,编码必须指定,关闭交给 try-with-resources。
