printstream适合全局重定向system.out,需自动刷新和指定编码;printwriter适合按需写入文件,不劫持控制台;生产环境应使用slf4j+logback等日志框架。

直接用 PrintStream 或 PrintWriter 重定向控制台输出,本质是替换或接管 System.out 的行为,但两者定位不同、用法不能互换——关键不是“怎么写代码”,而是“为什么这么用”。
PrintStream:适合全局劫持 System.out
它继承自字节流,能直接处理原始字节,也支持自动刷新和编码指定。重定向后,所有 System.out.println()(包括第三方库、未捕获异常堆栈)都会写入目标位置。
- 必须启用自动刷新:
new PrintStream(file, true),否则程序崩溃时最后一段日志可能丢失 - 强烈建议指定字符集:
new PrintStream(file, true, "UTF-8"),避免中文乱码 - 重定向后无法“局部生效”,若需临时切换,得先保存原
System.out,再手动恢复,多线程下易出错 - 典型场景:调试脚本、一次性命令行工具、运行快照导出,不推荐用于生产环境日志
PrintWriter:适合按需写入特定文件
它面向字符,天然适配字符串和日志消息,不用于劫持 System.out,而是作为独立通道精准控制日志落点。
- 构造时用
new FileWriter(file, true)可追加写入,适合告警日志、操作记录等累积型内容 - 配合
e.printStackTrace(pw)能把异常堆栈完整写入指定文件,比全局重定向更安全、更可控 - 务必使用 try-with-resources 自动关闭:
try (PrintWriter pw = new PrintWriter(...)) { ... },否则缓冲区内容可能不落盘 - 不干扰
System.out,业务打印仍走控制台,日志写入由你显式触发
别绕过日志框架,这才是真正该用的
手写 PrintStream 或 PrintWriter 做日志,等于放弃上下文追踪、异步写入、滚动归档、敏感脱敏等运维必需能力。
- 用 SLF4J + Logback,只需配置一个
FileAppender指向告警路径,调用logger.error("订单超时", e)即可 - 通过 MDC 注入
traceId、userId,每条日志自带业务上下文 - 用
ThresholdFilter或自定义 Filter 实现“仅 error 级别且含 'ALERT' 标签才写入告警文件” - Logback 自动按天切分、压缩旧日志,不用自己拼时间戳、管文件名











