Java PrintStream 详解:从基础用法到实战技巧

1. 引言

在 Java 日常开发中,PrintStream 是最常用的输出流之一。无论是控制台打印、日志输出,还是文件写入,都能看到它的身影。本文将从基础概念出发,结合代码示例,系统讲解 PrintStream 的核心用法、常见陷阱和实战技巧。

2. 什么是 PrintStream

PrintStreamjava.io 包中的一个字节输出流类,它继承自 FilterOutputStream。它的核心特点是:

  • 自动刷新:部分构造方法支持自动刷新缓冲区。
  • 便捷打印方法 :提供 print()println() 系列方法,支持各种基本数据类型和对象。
  • 不抛受检异常 :写入方法不会抛出 IOException,而是通过内部状态记录错误。

最典型的实例就是 System.out,它就是一个 PrintStream 对象,默认输出到控制台。

3. 创建 PrintStream

可以通过多种方式创建 PrintStream 实例,常见的有以下几种:

java 复制代码
import java.io.FileOutputStream;
import java.io.PrintStream;

public class CreatePrintStream {
    public static void main(String[] args) throws Exception {
        // 方式一:包装已有输出流
        PrintStream ps1 = new PrintStream(System.out);

        // 方式二:指定文件名,自动创建文件
        PrintStream ps2 = new PrintStream("output.txt");

        // 方式三:指定文件输出流,并开启自动刷新
        PrintStream ps3 = new PrintStream(new FileOutputStream("log.txt"), true);

        // 方式四:指定字符集
        PrintStream ps4 = new PrintStream("data.txt", "UTF-8");

        ps1.println("Hello PrintStream");
        ps1.close();
    }
}

其中,第二个参数 autoFlushtrue 时,遇到换行符或字节数组写入时会自动刷新缓冲区。

4. 常用方法详解

PrintStream 提供了丰富的打印方法,下面按类别介绍最常用的部分。

4.1 print 与 println

print() 输出内容但不换行,println() 输出内容后自动换行。两者都支持多种重载形式:

java 复制代码
public class PrintMethods {
    public static void main(String[] args) {
        int num = 42;
        double pi = 3.14159;
        String name = "Java";
        Object obj = new Object();

        System.out.print("数字: ");
        System.out.println(num);

        System.out.println("浮点数: " + pi);
        System.out.println("字符串: " + name);
        System.out.println("对象: " + obj);
    }
}

4.2 printf 格式化输出

printf() 支持类似 C 语言的格式化输出,是构建整齐文本的利器:

java 复制代码
public class PrintfDemo {
    public static void main(String[] args) {
        String product = "笔记本电脑";
        double price = 5999.5;
        int stock = 120;

        System.out.printf("商品:%s,价格:%.2f 元,库存:%d 件%n", product, price, stock);
        System.out.printf("百分比:%.1f%%%n", 87.35);
    }
}

常用占位符包括 %s(字符串)、%d(整数)、%f(浮点数)、%n(换行符)。

4.3 write 方法

作为输出流,PrintStream 也支持底层字节写入:

java 复制代码
public class WriteDemo {
    public static void main(String[] args) {
        PrintStream ps = new PrintStream(System.out);
        byte[] data = {65, 66, 67, 10}; // A B C 换行
        ps.write(data, 0, data.length);
        ps.flush();
        ps.close();
    }
}

5. 重定向 System.out

通过 System.setOut() 可以将标准输出重定向到文件或其他流,这在日志记录和测试场景中非常实用:

java 复制代码
import java.io.FileOutputStream;
import java.io.PrintStream;

public class RedirectOut {
    public static void main(String[] args) throws Exception {
        PrintStream fileOut = new PrintStream(new FileOutputStream("app.log"), true);
        System.setOut(fileOut);

        System.out.println("这条日志会写入文件");
        System.out.println("而不是显示在控制台");

        // 恢复标准输出
        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
        System.out.println("控制台输出恢复");
    }
}

6. 常见陷阱与注意事项

使用 PrintStream 时,有几个容易踩坑的地方需要特别留意。

6.1 异常被吞掉

PrintStream 的写入方法不抛出 IOException,错误会被记录在内部状态中。需要通过 checkError() 主动检查:

java 复制代码
public class CheckErrorDemo {
    public static void main(String[] args) {
        PrintStream ps = new PrintStream(System.out);
        ps.println("写入内容");
        if (ps.checkError()) {
            System.err.println("输出过程中发生错误");
        }
        ps.close();
    }
}

6.2 字符集问题

默认构造方法使用平台默认字符集,在跨平台场景下可能导致乱码。建议显式指定字符集:

java 复制代码
PrintStream ps = new PrintStream("output.txt", StandardCharsets.UTF_8);

6.3 资源关闭

包装了其他流的 PrintStream 在关闭时,会同时关闭底层流。如果不想关闭底层流,可以使用 System.out 或自行管理生命周期。

7. 实战:日志记录工具

下面结合前面的知识,实现一个简单的日志工具类:

java 复制代码
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class SimpleLogger {
    private final PrintStream out;

    public SimpleLogger(String filePath) throws Exception {
        this.out = new PrintStream(new FileOutputStream(filePath, true), true, "UTF-8");
    }

    public void info(String message) {
        log("INFO", message);
    }

    public void error(String message) {
        log("ERROR", message);
    }

    private void log(String level, String message) {
        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        out.printf("[%s] [%s] %s%n", time, level, message);
    }

    public void close() {
        out.close();
    }

    public static void main(String[] args) throws Exception {
        SimpleLogger logger = new SimpleLogger("app.log");
        logger.info("应用启动");
        logger.error("数据库连接失败");
        logger.close();
    }
}

8. 总结

PrintStream 凭借便捷的打印方法和灵活的重定向能力,在 Java 输出场景中占据重要地位。使用时需要注意异常检查、字符集指定和资源管理三个关键点。掌握这些内容,就能在日常开发中更加得心应手地处理输出需求。

相关推荐
吴声子夜歌1 小时前
ApacheCommons——commons-compress(解压缩工具)
java·apache
程序员清风1 小时前
聊聊怎么缓解找工作的焦虑感?
java·后端·面试
cui_ruicheng1 小时前
FastAPI 应用开发(二):请求响应、Pydantic 模型与依赖注入
python·fastapi·web
sunshine22 girl1 小时前
Java学习一 环境配置3 Idea的基本设置和插件
java·学习
guwentian1 小时前
手撕 MCP:用 TypeScript 从零写一个能跑的最小客户端(附可运行 demo)
开发语言·nodejs·mcp
DeepVisionary1 小时前
SoundHound 完成收购 LivePerson:股权对价 4300 万美元,实际总成本约 3.04 亿
python·自动化
会编程的吕洞宾1 小时前
LangChain4j RAG 分块策略实战:检索质量提升 80% 的 Chunking 调优全解
java·人工智能·后端
Sagittarius_A*1 小时前
【LitCTF2026】lit_ezsql
android·java·数据库
LayZhangStrive2 小时前
数据结构与算法 - 堆排序
java·数据结构·算法·排序算法·堆排序·大根堆