Java 的 PrintStream 类(即 java.io.PrintStream)能够让你将格式化的数据写入底层的 OutputStream。该类具备将 int、long 等基本数据类型转化为文本形式的能力,而非直接处理它们的字节值。这也正是它被命名为 PrintStream 的缘由,它会把原始数据转化为文本,就如同信息被打印到屏幕上(或是打印在纸张上)时呈现的样子。
以下是一个简单的 PrintStream 示例:
package com.hxstrive.java_io; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.PrintStream; public class PrintStreamExample { public static void main(String[] args) throws IOException { // 写出数据 try(PrintStream ps = new PrintStream("test.txt")){ ps.println("Hello, Java!"); ps.println((int)1024); ps.println(true); ps.println(3.1415d); } // 读取数据 try(BufferedInputStream in = new BufferedInputStream(new FileInputStream("test.txt"))) { byte[] buffer = new byte[1024]; int len = in.read(buffer); System.out.println(new String(buffer, 0, len)); } } }
运行输出:
Hello, Java! 1024 true 3.1415
上述示例,首先创建了一个连接到 OutputStream 的 PrintStream。其次,向 PrintStream 打印几个原始值,写入到 test.txt 文件。最后,通过 BufferedInputStream 读取 test.txt 文件的内容。
你或许对 Java 里两个广为人知的 PrintStream 实例并不陌生,它们就是 System.out 和 System.err。倘若你曾使用过这两个流中的任意一个,那实际上你就已经用过 PrintStream 了。
在 Java 中,PrintStream 类提供了功能强大的 format() 和 printf() 方法。这两个方法的功能是完全一致的,不过对于熟悉 C 语言的程序员而言,“printf” 这个名称会让他们感觉更为亲切。借助这些方法,你能够运用格式化字符串,以一种十分高级的方式将文本和数据进行融合。
示例:
package com.hxstrive.java_io; import java.io.PrintStream; public class PrintStreamPrintfExample { public static void main(String[] args) { // 定义一些不同类型的变量,用于后续格式化输出 String name = "Alice"; int age = 25; double height = 1.65; boolean isStudent = true; try(PrintStream ps = System.out) { // 输出基本信息,使用 %s 格式化字符串,%d 格式化整数 ps.printf("姓名: %s,年龄: %d 岁\n", name, age); // 输出带有小数的信息,使用 %.2f 格式化双精度浮点数,保留两位小数 ps.printf("姓名: %s,身高: %.2f 米\n", name, height); // 输出布尔值信息,使用 %b 格式化布尔值 ps.printf("姓名: %s,是否为学生: %b\n", name, isStudent); // 格式化输出带宽度的字符串,%-10s 表示左对齐,宽度为 10 ps.printf("|%-10s|%10s|\n", "姓名", "年龄"); ps.printf("|%-10s|%10d|\n", name, age); // 格式化输出日期信息,使用 %tF 格式化日期为 yyyy-MM-dd 格式 java.util.Date currentDate = new java.util.Date(); ps.printf("当前日期: %tF\n", currentDate); // 格式化输出时间信息,使用 %tT 格式化时间为 HH:mm:ss 格式 ps.printf("当前时间: %tT\n", currentDate); // 格式化输出带有前导零的整数,使用 %03d 表示宽度为 3,不足用 0 补齐 int number = 7; ps.printf("带有前导零的数字: %03d\n", number); } } }
运行输出:
姓名: Alice,年龄: 25 岁 姓名: Alice,身高: 1.65 米 姓名: Alice,是否为学生: true |姓名 | 年龄| |Alice | 25| 当前日期: 2025-04-07 当前时间: 14:57:38 带有前导零的数字: 007
PrintStream 类中的 format() 方法用于将格式化的字符串写入此输出流。它允许你使用格式化说明符来控制输出的格式,支持多种数据类型的格式化输出,例如整数、浮点数、字符串、日期等。
该方法有两个重载版本:
public PrintStream format(String format, Object... args):使用指定的格式字符串和参数生成格式化的输出。
public PrintStream format(Locale l, String format, Object... args):使用指定的语言环境、格式字符串和参数生成格式化的输出。
示例:
package com.hxstrive.java_io; import java.io.PrintStream; import java.util.Date; public class PrintStreamFormatExample { public static void main(String[] args) { // 定义一些变量用于格式化输出 String name = "John"; int age = 30; double salary = 5000.50; Date currentDate = new Date(); try(PrintStream ps = System.out) { // 示例 1:格式化输出字符串和整数 // %s 用于格式化字符串,%d 用于格式化十进制整数 ps.format("姓名: %s,年龄: %d\n", name, age); // 示例 2:格式化输出浮点数,保留两位小数 // %.2f 表示格式化浮点数,保留两位小数 ps.format("姓名: %s,薪水: %.2f\n", name, salary); // 示例 3:格式化输出日期 // %tF 用于格式化日期为 yyyy-MM-dd 格式 ps.format("当前日期: %tF\n", currentDate); // 示例 4:格式化输出带宽度和对齐的字符串 // %-10s 表示左对齐,宽度为 10 的字符串格式化 ps.format("|%-10s|%10d|\n", "姓名", age); ps.format("|%-10s|%10.2f|\n", name, salary); } } }
运行结果:
姓名: John,年龄: 30 姓名: John,薪水: 5000.50 当前日期: 2025-04-07 |姓名 | 30| |John | 5000.50|
注意,format() 方法里,格式化字符串是由普通字符和格式说明符构成的。格式说明符以 % 开头,用于指定如何格式化相应的参数。以下是常见的格式说明符及其作用:
格式说明符 | 说明 | 示例 |
%b、%B | 用于格式化布尔类型的值。%b输出小写形式,%B输出大写形式。 | System.out.format("%b", true); 输出 true |
%s、%S | 用于格式化字符串类型的值。%s输出小写形式(若适用),%S输出大写形式(若适用)。 | System.out.format("%s", "hello"); 输出 hello |
%c、%C | 用于格式化字符类型的值。%c输出小写形式,%C输出大写形式。 | System.out.format("%c", 'A'); 输出 A |
整数类型
格式说明符 | 说明 | 示例 |
%d | 用于格式化十进制整数。 | System.out.format("%d", 123); 输出 123 |
%o | 用于格式化八进制整数。 | System.out.format("%o", 123); 输出 173 |
%x、%X | 用于格式化十六进制整数。%x输出小写字母,%X输出大写字母。 | System.out.format("%x", 255); 输出 ff |
浮点类型
格式说明符 | 说明 | 示例 |
%f | 用于格式化十进制浮点数。默认保留 6 位小数。 | System.out.format("%f", 3.14159); 输出 3.141590 |
%e、%E | 用于格式化科学计数法表示的浮点数。%e输出小写 e,%E输出大写 E。 | System.out.format("%e", 1234.56); 输出 1.234560e+03 |
%g、%G | 根据数值大小自动选择 %f或 %e格式。%g输出小写形式,%G输出大写形式。 | System.out.format("%g", 1234.56); 输出 1234.56 |
格式说明符 | 说明 | 示例 |
%t | 这是日期和时间格式化的前缀,后面需要跟具体的日期时间转换字符。 | |
%tY | 输出年份,4 位数字。 | System.out.format("%tY", new java.util.Date()); 输出如 2024 |
%ty | 输出年份的后两位数字。 | System.out.format("%ty", new java.util.Date()); 输出如 24 |
%tm | 输出月份,两位数字(01 - 12)。 | System.out.format("%tm", new java.util.Date()); 输出如 04 |
%td | 输出日期,两位数字(01 - 31)。 | System.out.format("%td", new java.util.Date()); 输出如 07 |
%tH | 输出 24 小时制的小时数,两位数字(00 - 23)。 | System.out.format("%tH", new java.util.Date()); 输出如 14 |
%tM | 输出分钟数,两位数字(00 - 59)。 | System.out.format("%tM", new java.util.Date()); 输出如 30 |
%tS | 输出秒数,两位数字(00 - 60)。 | System.out.format("%tS", new java.util.Date()); 输出如 45 |
%tF | 等价于 %tY-%tm-%td,输出 yyyy-MM-dd格式的日期。 | System.out.format("%tF", new java.util.Date()); 输出如 2024-04-07 |
%tT | 等价于 %tH:%tM:%tS,输出 HH:mm:ss格式的时间。 | System.out.format("%tT", new java.util.Date()); 输出如 14:30:45 |
格式说明符 | 说明 | 示例 |
%% | 输出一个 %字符。 | System.out.format("比例: 50%%"); 输出 比例: 50% |
%n | 输出平台特定的换行符。 | System.out.format("第一行%n第二行"); 输出换行后的两行内容 |
除了基本的格式说明符,还可以使用修饰符来进一步控制输出格式,常见修饰符如下:
宽度:在 % 后指定一个正整数,表示输出的最小宽度。例如 %5d 表示输出的整数至少占 5 个字符宽度。
精度:对于浮点数,在宽度后加 . 和数字表示保留的小数位数,如 %.2f 表示保留两位小数。
对齐:- 表示左对齐,例如 %-10s 表示左对齐且宽度为 10 的字符串输出。
正负号:+ 表示输出正负号,例如 %+d 会为正数也加上 + 号。
前导零:0 表示用 0 填充宽度,例如 %05d 会在不足 5 位的整数前补 0。
当你完成向 PrintStream 写入数据的操作后,请务必记得将其关闭。需要注意的是,关闭 PrintStream 时,它所写入的 OutputStream 实例也会随之关闭。
若要关闭 PrintStream,只需调用其 close() 方法即可。例如:
printStream.close();
您还可以使用 Java 7 中引入的 try-with-resources 结构。例如
OutputStream output = new FileOutputStream("data.bin"); try(PrintStream printStream = new PrintStream(output)){ printStream.writeInt(123); //... }
需留意,此处不再有任何显式的 close() 方法调用,因为 try-with-resources 结构已自动处理了资源关闭问题。
另外,首个 FileOutputStream 实例并非在 try-with-resources 代码块中创建,这表明 try-with-resources 块不会自动关闭该 FileOutputStream 实例。不过,当 PrintStream 关闭时,它会同时关闭其写入数据的 OutputStream 实例,所以 FileOutputStream 实例会在 PrintStream 关闭时一并关闭。