PrintStream 字节打印流
你有没有想过:System.out.println("Hello") 这行代码,背后的原理是什么?
答案是 PrintStream。
System.out 和 System.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 的区别
| 对比 | PrintStream | PrintWriter |
|---|---|---|
| 底层 | 字节流 | 字符流 |
| System.out | PrintStream | — |
| 编码控制 | 不支持(需包装) | 支持(构造时指定) |
| 构造函数 | PrintStream(File/String/OutputStream) | PrintWriter(Writer/File/String/OutputStream) |
| 推荐场景 | 二进制数据、调试输出 | 文本文件写入 |
记住这个选择:
System.out用的是PrintStream。 写文本文件,更推荐PrintWriter。
