理解 FileOutputStream 的定位与适用场景
掌握五种构造方式,特别是追加模式的使用
能够正确写入二进制数据(如图片、音频)
熟悉核心写入方法与资源管理机制
了解与 NIO 的集成能力
FileOutputStream 是 Java 中用于向文件写入原始字节数据的输出流,继承自 OutputStream。它是处理二进制文件(如图像、音频、视频、压缩包)的标准工具。
重要提示:虽然可以用它写入文本,但不推荐!应使用
FileWriter或OutputStreamWriter(可指定编码),避免跨平台乱码问题。
核心特性
字节级操作:每次写入 1 个或多个 byte(8 位)
无缓冲:直接写入磁盘,频繁小量写入性能较差
平台无关:自动适配不同操作系统的文件系统
支持追加模式:通过构造器参数控制覆盖或追加
支持 NIO:可通过 getChannel() 获取 FileChannel 进行高效 I/O
public class FileOutputStream extends OutputStream继承 OutputStream:获得 write()、flush()、close() 等基础方法
实现 Closeable 和 Flushable:支持 try-with-resources 和强制刷新
封装底层文件写入:将 Java 字节流映射到操作系统文件句柄
// 覆盖模式(默认)
FileOutputStream fos1 = new FileOutputStream("log.txt");
FileOutputStream fos2 = new FileOutputStream(new File("data.bin"));
// 追加模式
FileOutputStream fos3 = new FileOutputStream("log.txt", true);
FileOutputStream fos4 = new FileOutputStream(new File("backup.zip"), true);
// 从标准输出(极少使用)
FileOutputStream fos5 = new FileOutputStream(FileDescriptor.out);最佳实践:明确指定
append参数,避免意外覆盖重要数据
注意:
FileOutputStream本身无缓冲,所以flush()是空操作。若需缓冲,应包装BufferedOutputStream
写入文本数据
import java.io.*;
public class FileOutputStreamExample {
public static void main(String[] args) {
String message = "Hello, Java FileOutputStream!";
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
// 将字符串转为字节数组(使用平台默认编码)
byte[] data = message.getBytes();
// 写入文件
fos.write(data);
System.out.println("数据已成功写入 output.txt");
} catch (IOException e) {
System.err.println("写入失败: " + e.getMessage());
}
}
}警告:
getBytes()使用系统默认编码,跨平台可能乱码!生产环境应使用:byte[] data = message.getBytes(StandardCharsets.UTF_8);
二进制文件写入(图片保存)
以下程序演示如何将字节数组保存为图片文件:
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
public class SaveImage {
public static void main(String[] args) {
try {
// 假设我们有一个字节数组(例如从网络下载的图片数据)
byte[] imageData = Files.readAllBytes(Paths.get("source.jpg"));
// 保存为新文件
try (FileOutputStream fos = new FileOutputStream("saved_image.jpg")) {
fos.write(imageData); // 直接写入原始字节
}
System.out.println("图片已保存为 saved_image.jpg");
} catch (IOException e) {
System.err.println("文件操作失败: " + e.getMessage());
}
}
}日志记录
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class LogWriter {
private static final String LOG_FILE = "app.log";
public static void log(String message) {
String timestamp = LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
String logEntry = "[" + timestamp + "] " + message + System.lineSeparator();
try (FileOutputStream fos = new FileOutputStream(LOG_FILE, true)) {
fos.write(logEntry.getBytes()); // 追加到文件末尾
} catch (IOException e) {
System.err.println("日志写入失败: " + e.getMessage());
}
}
public static void main(String[] args) {
log("应用程序启动");
log("用户登录成功");
log("数据处理完成");
System.out.println("日志已追加到 app.log");
}
}app.log 内容:
[2026-01-30 13:45:01] 应用程序启动
[2026-01-30 13:45:02] 用户登录成功
[2026-01-30 13:45:03] 数据处理完成FileOutputStream 专为二进制数据写入设计,文本写入请用 FileWriter
五种构造器,追加模式通过 boolean append 参数控制
核心方法:write()(单字节 / 数组)、close()、getChannel()
无内置缓冲,性能敏感场景需包装 BufferedOutputStream
必须使用 try-with-resources 确保资源释放
通过 getChannel() 支持 NIO 高级功能(内存映射、异步 I/O)
为什么 FileOutputStream 的 flush() 方法实际上不做任何事情?在什么情况下我们需要手动调用 flush()?
如果向一个已存在的文件写入数据时未指定追加模式,会发生什么?如何避免意外覆盖重要文件?
在高并发日志系统中,直接使用 FileOutputStream 追加写入是否安全?为什么?应如何改进?