Java中System.out默认输出到控制台,可通过System.setOut(new PrintStream(new FileOutputStream("log", true), true, "UTF-8"))重定向至UTF-8编码的日志文件,需在首次使用前调用并注意路径、编码、资源释放及线程安全问题。

Java 中的 System.out 默认输出到控制台,但开发或运维时经常需要将其重定向到文件(如日志),便于排查问题或归档。这不难实现,关键是理解原理并注意几个易错点。
为什么不能直接用 PrintStream 包装文件流?
可以,但要注意:一旦重定向,所有 System.out.println() 都会写入文件,控制台不再显示——这对调试可能造成困扰。更稳妥的做法是同时保留控制台输出(可选),或仅在特定环境(如生产)启用重定向。
常见错误包括:
- 未关闭旧的
PrintStream,导致资源泄漏; - 使用相对路径写日志,程序迁移后路径失效;
- 未处理中文乱码(尤其 Windows 系统默认编码非 UTF-8);
- 多线程环境下未加锁,造成日志内容错乱(
PrintStream本身线程安全,但自定义包装需留意)。
最简可靠方式:用 FileOutputStream + PrintStream 重定向
以下代码可在应用启动早期(如 main 方法开头或 static 块中)执行:
File logFile = new File("app-output.log");
// true 表示追加模式,避免每次覆盖
FileOutputStream fos = new FileOutputStream(logFile, true);
// 显式指定 UTF-8 编码,防止中文乱码
PrintStream ps = new PrintStream(fos, true, "UTF-8");
System.setOut(ps);
说明:
-
System.setOut(ps)是核心调用,必须在任何System.out使用前执行; - 推荐使用绝对路径或基于
System.getProperty("user.dir")构建路径; - 如果希望同时输出到控制台和文件,可用
TeeOutputStream(Apache Commons IO 提供)或自行封装一个双写 PrintStream。
进阶建议:结合日志框架统一管理
单纯重定向 System.out 属于“临时方案”。长期项目应迁移到成熟日志框架(如 Log4j2、SLF4J + Logback):
- 它们天然支持按级别过滤、滚动归档、异步写入、结构化日志;
- 可通过桥接器(如
slf4j-simple或jul-to-slf4j)将System.out/err自动转为日志事件; - 避免混用
System.out.println()和 logger,保持日志风格统一。
若必须保留部分 System.out 输出(如脚本调用时需返回状态),可考虑只重定向 System.err,或用 System.setErr() 单独处理错误流。
验证与收尾注意事项
重定向生效后,可通过以下方式验证:
- 运行程序,检查日志文件是否生成、内容是否完整、中文是否正常;
- 确认控制台是否按预期静默(或仍有输出);
- 程序退出前,可选择性调用
System.out.close()(但通常由 JVM 在退出时自动清理); - 如需恢复原始输出,保存初始
System.out引用:PrintStream originalOut = System.out;
后续可用System.setOut(originalOut)恢复。

















