FileOutputStream构造函数的第二个boolean参数控制写入位置:true表示每次write()自动定位到文件末尾(追加),false则从开头覆盖;它不提供线程安全、缓冲、编码或换行支持。

FileOutputStream 构造函数的第二个 boolean 参数到底控制什么
这个 true 参数不是“开启追加模式”的开关,而是决定底层文件指针是否从文件末尾开始写入。当传 true 时,JVM 会调用系统级的 O_APPEND 标志(Linux/Unix)或等效机制(Windows),确保每次 write() 都自动定位到当前文件末尾——哪怕其他进程也在同时写这个文件。传 false(默认)则每次写都从文件开头覆盖,极易丢失历史日志。
必须配合 try-with-resources 才能避免日志截断
常见错误是手动 close() 失败或忘记调用,导致缓冲区未刷盘、文件句柄泄漏,甚至下一次以 true 重开时因旧句柄未释放而出现不可预期行为。更隐蔽的问题是:如果在写入中途异常退出且没正确关闭,部分日志可能卡在 OS 缓冲区里,下次启动时看似“追加”,实则丢了最后几条。
- 始终用
try (FileOutputStream fos = new FileOutputStream("app.log", true)) { ... } - 不要在循环里反复 new/close —— 每次新建都会触发系统调用,性能差且增加截断风险
- 如需高频写入,应在单个
FileOutputStream实例上复用,并搭配BufferedOutputStream
换行符不写进文件,日志就全挤在一行
FileOutputStream 是字节流,它不管换行逻辑。如果你只写字符串内容,比如 fos.write("INFO: start".getBytes()),那所有日志会连成一长串,根本没法读。Java 不会自动加 \n,也不识别平台换行习惯。
- 显式写入换行:用
fos.write("\n".getBytes(StandardCharsets.UTF_8))或直接fos.write('\n') - 更稳妥的做法是封装一层,比如
fos.write((msg + "\n").getBytes(StandardCharsets.UTF_8)) - 别依赖
PrintStream的println()—— 它内部虽然加了换行,但会额外做字符编码转换,且异常处理不如原生流清晰
多线程并发写同一个文件会乱序,但不会损坏文件
多个线程共用一个 FileOutputStream 实例写日志,即使开了 true,也会因线程调度导致日志行交错(比如 A 线程写一半被切走,B 线程插进来)。但操作系统保证每次 write() 调用是原子的(对小数据),所以不会出现半个汉字或字节错乱,只是顺序不可控。
- 生产环境务必用
synchronized块或ReentrantLock包裹写操作 - 更推荐用
java.util.logging或 Log4j 这类成熟框架——它们内置了线程安全的追加写和滚动策略 - 注意:
FileOutputStream本身不是线程安全的,不能靠true参数解决并发问题
true 只影响写入位置,不提供缓冲、编码、线程安全或日志格式支持。它只是一个底层开关,离可用的日志系统还差得很远。


















