Skip to content

PrintStream 字节打印流

你有没有想过:System.out.println("Hello") 这行代码,背后的原理是什么?

答案是 PrintStream

System.outSystem.err 都是 PrintStream。当你写 System.out.println("xxx") 时,实际上是在调用 PrintStream 的方法。

System.out 的本质

java
// System.out 是一个 PrintStream
PrintStream out = System.out;

// 所以这两行等价:
System.out.println("Hello");
out.println("Hello");

// PrintStream 可以重定向到文件
PrintStream fileOut = new PrintStream("app.log");
System.setOut(fileOut); // 之后所有 System.out.println 都写到文件
System.out.println("这条日志会写进文件");

基本用法

java
// 打印到控制台
System.out.println("Hello World");
System.out.print("不换行 ");
System.out.println("换行");

// 格式化打印
System.out.printf("姓名: %s, 年龄: %d, 身高: %.2f%n", "张三", 25, 1.75);

printf 格式化符号

符号说明示例
%d十进制整数printf("%d", 42)42
%f浮点数printf("%.2f", 3.14159)3.14
%s字符串printf("%s", "hello")hello
%c字符printf("%c", 'A')A
%b布尔printf("%b", true)true
%x / %o十六进制 / 八进制printf("%x", 255)ff
%%输出百分号printf("100%%")100%
%n平台换行符推荐用 %n 而不是 \n

宽度和对齐

java
System.out.printf("%10s", "Hello");    // 右对齐,总宽度 10 → "     Hello"
System.out.printf("%-10s", "Hello");   // 左对齐,总宽度 10 → "Hello     "
System.out.printf("%05d", 42);         // 补零,宽度 5 → "00042"
System.out.printf("%.2f", 3.14159);    // 小数位数 → "3.14"

写文件

java
// 方式 1:自动 flush 的 PrintStream
try (PrintStream ps = new PrintStream(
        new BufferedOutputStream(
            new FileOutputStream("output.txt")), true)) { // true = autoFlush
    ps.println("第一行");      // 自动 flush
    ps.printf("x = %d%n", 100); // 自动 flush
}

// 方式 2:非自动 flush
try (PrintStream ps = new PrintStream(
        new FileOutputStream("output.txt"))) {
    ps.println("内容");
    ps.flush(); // 手动 flush
}

PrintStream 的特点

特点 1:不抛 IOException

java
// ❌ OutputStream:写失败会抛 IOException
try (OutputStream out = new FileOutputStream("out.txt")) {
    out.write("data".getBytes());
    // 如果磁盘满了,这里会抛 IOException
}

// ✅ PrintStream:不抛异常,但可以通过 checkError() 检测错误
PrintStream ps = new PrintStream("out.txt");
ps.println("data");
if (ps.checkError()) {
    // 写失败,但不会抛异常
}

特点 2:自动类型转换

java
PrintStream ps = new PrintStream("out.txt");
ps.println(42);           // int → "42"
ps.println(3.14);        // double → "3.14"
ps.println(true);        // boolean → "true"
ps.println('A');         // char → "A"
ps.println("hello");     // String → "hello"
ps.println(Arrays.asList(1, 2, 3)); // Object → "[1, 2, 3]"
// 所有类型都自动转成字符串

append() 方法

PrintStream 实现了 Appendable 接口:

java
PrintStream ps = new PrintStream("out.txt");
ps.append("Hello").append(' ').append("World"); // 链式调用

常见问题

中文编码

java
// ❌ 不指定编码,可能乱码
try (PrintStream ps = new PrintStream("output.txt")) {
    ps.println("你好");
}

// ✅ 指定 UTF-8 编码
try (PrintStream ps = new PrintStream(
        new BufferedOutputStream(
            new FileOutputStream("output.txt")))) {
    ps.println("你好");
}
// PrintStream 本身不支持指定编码,需要包装一层 BufferedOutputStream

和 PrintWriter 的区别

对比PrintStreamPrintWriter
底层字节流字符流
System.outPrintStream
编码控制不支持(需包装)支持(构造时指定)
构造函数PrintStream(File/String/OutputStream)PrintWriter(Writer/File/String/OutputStream)
推荐场景二进制数据、调试输出文本文件写入

记住这个选择

System.out 用的是 PrintStream。 写文本文件,更推荐 PrintWriter

基于 VitePress 构建