printstream适合全局重定向system.out(如导出运行快照),printwriter适合按需写入特定文件(如异常堆栈),但真实项目应使用slf4j+logback等日志框架统一管理,以保障可运维性。

PrintStream 和 PrintWriter 都能实现控制台输出的重定向,但它们适用场景不同、行为有细节差异,不能混用或随意替换。关键不是“能不能重定向”,而是“要不要全局重定向”以及“重定向后是否可控、可维护”。
PrintStream 重定向 System.out 是全局劫持
调用 System.setOut(new PrintStream(file)) 后,所有线程中后续的 System.out.println()、第三方库的打印语句、甚至未捕获异常的默认堆栈,都会写入该文件——它不识别日志级别,也不区分业务模块。
- 必须显式启用自动刷新(
new PrintStream(file, true)),否则程序异常退出时最后一段日志可能丢失 - 推荐指定字符集,如
new PrintStream(file, true, "UTF-8"),避免中文乱码 - 无法安全地“只对某段代码生效”;若想临时切换再切回,需手动保存原
System.out并恢复,多线程下易出竞态 - 不建议用于生产环境的日志记录,仅适合简单脚本、调试工具或单次运行的命令行程序
PrintWriter 更适合按需写入特定日志文件
PrintWriter 不用于劫持 System.out,而是作为独立输出通道,配合 try-with-resources 精确控制哪条日志写到哪个文件。
- 构造时传入
FileWriter(file, true)可追加写入,适合告警日志等需要累积记录的场景 - 支持字符级操作,天然适配字符串、日志消息,无需处理编码转换
- 配合
e.printStackTrace(pw)可把异常堆栈定向写入指定文件,比全局重定向更精准、更安全 - 务必用
try (PrintWriter pw = ...)自动关闭,否则缓冲区内容可能未落盘
真正该用什么?别绕过日志框架
直接操作 PrintStream 或 PrintWriter 写日志,等于放弃上下文追踪、异步写入、滚动归档、敏感信息脱敏等关键能力。
- 用 SLF4J + Logback 时,只需配置一个专用的
FileAppender指向告警日志路径,并在代码中调用logger.error("订单超时", e) - 可在日志格式中嵌入 MDC 字段(如 traceId、userId),让每条日志自带业务上下文
- 通过
ThresholdFilter或自定义Filter实现“仅 error 级别且含 'ALERT' 标签才写入告警文件” - Logback 支持
TimeBasedRollingPolicy,自动按天切分、压缩旧日志,无需自己拼时间戳文件名
小结:选对方式,不是选哪个类
PrintStream 适合做 JVM 级输出流替换(如将整个应用 stdout 导出为运行快照);PrintWriter 适合在 catch 块里定向写异常详情;而真实项目中的日志,应该交给成熟框架统一管理——它不是更“高级”,而是更可靠、更可运维。











