要实现日志既实时显示在控制台又同步追加写入文件,需启用文件追加模式、开启自动刷新或及时flush,并避免多线程并发写同一文件流。

控制台日志本身不涉及“追加写入”——因为控制台是实时显示的流式输出,每次 System.out.println() 或 logger 输出都会立即刷新到终端界面,不存在“覆盖”或“追加”语义。但如果你的目标是:**让日志既实时显示在控制台,又同步、不丢失地追加写入到文件**,那关键在于合理搭配缓冲机制与输出流配置,避免因缓冲导致日志延迟落盘。
理解缓冲对“实时性”的影响
Java 的字符输出流(如 PrintWriter、BufferedWriter)默认带内部缓冲区。若不主动刷新,日志可能卡在内存里几秒甚至更久才写入文件,这就不算“实时”。而控制台输出(System.out)在多数终端中默认是行缓冲或无缓冲的,所以看起来“即时”,但这不代表文件端也同步。
要真正实现“控制台可见 + 文件追加 + 实时落盘”,需确保:
- 文件写入流启用追加模式(
new FileWriter("log.txt", true)) - 禁用或及时刷新缓冲(调用
flush(),或使用PrintWriter(OutputStream, true)的自动刷新构造) - 避免多线程并发写同一文件流(否则可能乱序或丢日志,建议用线程安全的日志框架或加锁)
用 PrintWriter + 自动刷新实现简易实时追加
这是轻量级场景下最直接的做法:绕过复杂日志框架,手动组合流,兼顾控制台和文件输出。
示例代码逻辑:
- 创建一个
FileWriter,传true启用追加 - 包装为
PrintWriter,并开启自动刷新(第二个参数为true) - 每次
println()会立刻触发flush(),保证内容即时写入文件 - 同时用
System.out.println()输出到控制台(二者独立,互不影响)
用 Logger + FileHandler 控制追加与刷新
若使用 java.util.logging,需显式配置 FileHandler 并管理缓冲行为:
- 构造
FileHandler("app.log", true)→ 启用追加 - 调用
fileHandler.setFormatter(new SimpleFormatter())统一日志格式 -
关键一步:默认
FileHandler不自动刷新,需设置fileHandler.setFlushAfterWrite(true)(Java 9+)或在每次logger.info()后手动fileHandler.flush() - 调用
logger.setUseParentHandlers(false)防止重复输出到控制台(如需控制台,另加ConsoleHandler)
为什么不用 BufferedOutputStream 手动 flush?
有人尝试用 BufferedOutputStream 包装 FileOutputStream 再套 PrintStream,但容易出错:
- 字节流(
OutputStream)不处理换行符编码,中文可能乱码 - 必须严格配对
write()+flush(),遗漏一次就卡住 -
BufferedOutputStream的flush()只刷到 OS 缓冲区,不保证落盘(getChannel().force(true)才能强制写入磁盘,但开销大)
因此,优先选字符流(FileWriter / PrintWriter)配合自动刷新,更稳妥。

















