【Java】I/O:PrintStream与PrintWriter核心区别
·
PrintStream 和 PrintWriter 是 Java I/O 中用于输出数据的两个重要包装类。它们最大的共同点是:它们都不会抛出检查型异常,这在日常开发中非常方便。
以下是它们的详细区别以及关于异常处理机制的深入解析。
一、 PrintStream 和 PrintWriter 的核心区别
最本质的区别在于:处理数据的方式不同(字节 vs 字符)。
| 特性 | PrintStream (字节流) | PrintWriter (字符流) |
|---|---|---|
| 继承体系 | 继承自 FilterOutputStream (字节流)。 |
继承自 Writer (字符流)。 |
| 数据处理 | 处理的是 字节。虽然它有打印字符串的方法,但底层本质上还是写字节。 | 处理的是 字符。专门用于处理文本输出,能够正确处理字符编码。 |
| 编码处理 | 它使用平台默认的字符编码将字符转换为字节。在国际化场景下容易导致乱码。 | 可以在构造时指定字符集,或者在构造时传入 OutputStream 时指定编码,对多语言支持更好。 |
| 典型应用 | System.out 就是 PrintStream 的实例。主要用于二进制数据输出或简单的控制台日志。 |
用于写入文本文件、网络响应等需要处理字符编码的场景。 |
| 自动刷新 | 只有在写入字节数组、调用 println 或写入换行符时,如果开启了自动刷新才会触发。 |
只有在调用 println, printf, 或 format 方法时,如果开启了自动刷新才会触发。 |
什么时候用哪个?
1.使用 PrintStream:当你需要处理二进制数据,或者你正在编写类似 System.out 这样的底层输出工具时。
2. 使用PrintWriter:绝大多数情况下,编写文本文件、网页响应或日志时,应该首选 PrintWriter。因为它能更好地处理字符编码(UTF-8等),避免中文乱码问题。
二、 异常处理机制
这是这两个类最独特的设计之一。
1. “吞掉”异常的设计
普通的 I/O 流(如 FileOutputStream 或 BufferedWriter)在写入失败时(如磁盘满、文件被占用)会抛出 IOException。调用者必须通过 try-catch 捕获或声明抛出。
但是,PrintStream 和 PrintWriter 的方法(如 print(), println(), write())不会抛出 IOException。
为什么不抛出?
设计初衷是为了简化编程。在打印日志或控制台输出时,如果每次都要写 try-catch 会非常繁琐。Java 设计者认为这些操作通常不应该中断程序流程,所以选择了“静默失败”。
2. 如何检查错误?
既然方法不抛异常,那怎么知道写入成功没有?
这两个类都提供了一个方法:checkError()。
- 它会刷新流。
- 它返回一个
boolean值:如果底层流曾经发生过错误,则返回true;否则返回false。 - 一旦发生错误,内部的错误标志位就会被设置,后续调用
checkError()将一直返回true(除非调用了特定的内部清除方法,通常不可达)。
3. 代码示例
普通流的异常处理(麻烦):
try {
FileWriter fw = new FileWriter("test.txt");
fw.write("Hello"); // 必须处理 IOException
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
PrintStream/PrintWriter 的异常处理(简洁但有隐患):
// 构造时仍需处理 FileNotFoundException
try (PrintWriter pw = new PrintWriter("test.txt")) {
pw.println("Hello World"); // 这里不需要 try-catch,编译通过
pw.println(123);
// 但是,如果这里写入失败(比如磁盘满),程序不会报错,继续往下跑!
// 我们需要手动检查:
if (pw.checkError()) {
System.out.println("写入文件发生错误!");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
三、 总结与最佳实践
- 优先选择
PrintWriter:在处理文本输出(特别是写文件或网络Socket)时,PrintWriter更合适,因为它支持指定编码,避免乱码。 - 注意构造函数的异常:虽然
print方法不抛异常,但构造函数(如new PrintWriter("file.txt"))会抛出FileNotFoundException,这个必须捕获。 - 谨慎对待“静默失败”:
- 对于日志记录,静默失败通常是可以接受的(日志写不进去不应该崩掉业务系统)。
- 对于关键业务数据(如交易记录、入库单据),不要依赖
PrintWriter或PrintStream,因为它们可能会丢数据且不报错。此时应使用普通的BufferedWriter或FileOutputStream,并严格处理IOException。
更多推荐




所有评论(0)