Java打印流案例怎么输出内容

wen java案例 20

Java打印流案例:如何高效输出内容?从入门到实战

目录导读

  • 打印流的核心概念与作用

    Java打印流案例怎么输出内容

  • 标准打印流:System.out与System.err

  • 自定义打印流:PrintStream与PrintWriter详解

  • 实战案例:格式化输出、文件打印与重定向

  • 常见问题与性能优化

  • 问答环节


打印流的核心概念与作用

在Java I/O体系中,打印流(PrintStream与PrintWriter)是最常用的输出工具之一,它们本质上是装饰流,封装了底层的字节或字符输出流,提供了便捷的打印方法(如print()println()printf()),无论你是输出到控制台、文件还是网络,打印流都能简化字符串、数字、对象等数据的输出过程。

核心优势

  • 自动刷新:支持自动刷新缓冲区(autoFlush)
  • 异常处理:内部捕获IOException,避免因输出失败导致程序中断(但可通过checkError()检查)
  • 格式化支持:通过printf()实现类似C语言的格式化输出

小贴士:Java的System.out本质就是一个PrintStream对象,默认连接到控制台。


标准打印流:System.out与System.err

1 System.out

最常用的打印流,用于输出正常信息,示例:

public class OutDemo {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
        System.out.print("不会换行");
        System.out.printf("格式化:%s 年龄 %d", "张三", 25);
    }
}

注意System.out默认使用平台编码,中文可能乱码,可通过-Dfile.encoding=UTF-8解决。

2 System.err

用于输出错误信息,与System.out独立,默认输出到控制台但线程安全级别不同,示例如下:

try {
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.err.println("发生除零错误:" + e.getMessage());
}

实际开发建议:将程序标准输出与错误输出分开重定向到不同日志文件,更利于问题排查。

核心问答

问:System.out和System.err能重定向到文件吗?
:可以,通过System.setOut(new PrintStream(new FileOutputStream("out.txt")))即可,注意要捕获FileNotFoundException


自定义打印流:PrintStream与PrintWriter详解

1 PrintStream

处理字节流,支持自动刷新,常用于二进制数据场景,构造函数常用:

PrintStream(OutputStream out)  // 默认无自动刷新
PrintStream(OutputStream out, boolean autoFlush)  // 指定自动刷新
PrintStream(OutputStream out, boolean autoFlush, String encoding)  // 指定编码

示例:输出到文件并自动刷新

try (PrintStream ps = new PrintStream(new FileOutputStream("log.txt"), true)) {
    ps.println("这是一条日志");
    ps.printf("当前时间:%tF", System.currentTimeMillis());
} catch (FileNotFoundException e) {
    e.printStackTrace();
}

2 PrintWriter

处理字符流,支持国际化字符编码,推荐用于文本输出,构造方法:

PrintWriter(Writer out) 
PrintWriter(OutputStream out, boolean autoFlush) 
PrintWriter(String fileName, String csn) // 直接指定文件名与编码

示例:带编码的文件输出

try (PrintWriter pw = new PrintWriter("output.txt", "UTF-8")) {
    pw.println("中文内容");
    pw.printf("数值:%.2f", 123.456);
} catch (IOException e) {
    e.printStackTrace();
}

核心区别对比

特性 PrintStream PrintWriter
处理数据 字节流 字符流
自动刷新 支持(写入字节数组或换行时) 支持(调用println/printf时)
编码支持 需手动指定 构造时直接指定
推荐场景 二进制混合文本 纯文本国际化

实战案例:格式化输出、文件打印与重定向

案例1:表格格式化输出

使用printf()实现对齐:

System.out.printf("%-10s %-8s %-10s%n", "姓名", "年龄", "城市");
System.out.printf("%-10s %-8d %-10s%n", "李四", 28, "北京");
System.out.printf("%-10s %-8d %-10s%n", "王五", 22, "上海");

输出效果:

姓名        年龄       城市        
李四        28         北京        
王五        22         上海        

案例2:日志文件打印(带时间戳)

import java.io.*;
import java.util.Date;
public class LogDemo {
    public static void main(String[] args) {
        try (PrintWriter log = new PrintWriter(
                new FileWriter("app.log", true), true)) {
            log.printf("[%tF %tT] 用户登录:%s%n", 
                       new Date(), new Date(), "admin");
            log.println("操作:查询订单");
        } catch (IOException e) {
            System.err.println("日志写入失败: " + e.getMessage());
        }
    }
}

案例3:输出重定向与恢复

// 保存原始流
PrintStream originalOut = System.out;
try (PrintStream fileOut = new PrintStream(
        new FileOutputStream("redirect.txt"))) {
    System.setOut(fileOut);
    System.out.println("这句话会写入文件,不会显示在控制台");
} catch (FileNotFoundException e) {
    e.printStackTrace();
} finally {
    // 恢复控制台输出
    System.setOut(originalOut);
}
System.out.println("这句话又回到控制台了");

核心问答

问:PrintStream和PrintWriter的自动刷新机制有什么差异?
:PrintStream在写入byte[]、调用println()或遇到换行符\n时触发刷新;PrintWriter在调用println()printf()format()时触发,两者都需要构造时设置autoFlush=true


常见问题与性能优化

问题1:性能瓶颈

直接使用System.out.println会在每次输出时触发系统调用,高并发场景下极其低效,优化方案:

  • 批量输出:先拼接字符串再一次性输出
  • 使用BufferedWriter:内部维护缓冲区,减少I/O次数
    StringBuilder sb = new StringBuilder();
    for (int i=0; i<10000; i++) {
      sb.append("line ").append(i).append("\n");
    }
    System.out.print(sb.toString()); // 一次性输出

问题2:中文乱码

通过指定编码解决:

PrintWriter pw = new PrintWriter(new OutputStreamWriter(
    System.out, "UTF-8"), true);
pw.println("中文测试");

问题3:自动关闭资源

使用try-with-resources确保流被正确关闭,避免资源泄漏:

try (PrintStream ps = new PrintStream(new FileOutputStream("test.dat"))) {
    // 使用ps
} // 自动关闭

性能对比测试

方法 10万行输出耗时
逐行System.out.println 约8秒
StringBuilder拼接后输出 约0.2秒
BufferedWriter包装后输出 约0.15秒

问答环节

问:PrintStream和PrintWriter的对象是否线程安全?
PrintStream的方法(如printlnprint)是同步的(synchronized),所以线程安全。PrintWriter的方法不是同步的,但内部包装的字符流可能是同步的(如BufferedWriter),推荐多线程场景使用PrintStream或自行同步。

问:如何将打印流输出到网络Socket?
:可以通过SocketOutputStream构造打印流:

Socket socket = new Socket("example.com", 8080);
PrintStream out = new PrintStream(socket.getOutputStream(), true, "UTF-8");
out.println("HTTP/1.1 200 OK\r\n\r\nHello");

问:打印流的checkError()方法有什么用?
:检查底层流是否发生错误,返回true表示有错误。

PrintStream ps = new PrintStream(System.out);
ps.println("测试");
if (ps.checkError()) {
    System.err.println("输出过程中发生错误");
}

问:在Spring Boot项目中,如何配置日志使用打印流?
:Spring Boot默认使用Logback或Log4j2,但可以通过System.setOutSystem.out重定向到日志框架。

import ch.qos.logback.core.OutputStreamAppender;
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
OutputStreamAppender appender = new OutputStreamAppender();
// 配置appender并设置到System.out

更推荐直接使用日志框架的API,而非System.out。

问:打印流的append()方法和print()有何区别?
append(CharSequence)返回PrintStream自身,支持链式调用,且内部调用print(),区别不大,但append符合Appendable接口规范。


通过本文学习,你应该能够灵活运用Java打印流解决各种输出需求。简单输出用System.out,文件输出用PrintWriter(指定编码),性能优化用批量拼接,在实际开发中,建议将打印流封装为工具类,统一管理日志格式与输出目标,如有其他疑问,欢迎在评论区交流。

抱歉,评论功能暂时关闭!