Java IO 中的 Reader(java.io.Reader)和 Writer(java.io.Writer)类的工作原理与 InputStream 和 OutputStream 非常相似,不同之处在于 Reader 和 Writer 都是基于字符的,用于读写文本。InputStream 和 OutputStream 是基于字节的,还记得吗?
Java Reader 是 Java IO API 中所有 Reader 的基类。子类包括 BufferedReader、PushbackReader、InputStreamReader、StringReader 等,如下图:
下面是一个简单的 Reader 示例:
package com.hxstrive.java_io.demo01; import java.io.FileReader; import java.io.Reader; /** * FileReader 示例 * @author hxstrive.com */ public class FileReaderDemo { public static void main(String[] args) { // 从 input.txt 文件读取数据 try(Reader reader = new FileReader("C:\\Users\\Administrator\\Desktop\\input.txt")) { int data = reader.read(); // 一次读取一个字符 while(data != -1){ char dataChar = (char) data; System.out.print(dataChar); // 打印 data = reader.read(); } } catch (Exception e) { e.printStackTrace(); } } }
请注意,InputStream 一次返回一个字节,即一个介于 0 和 255 之间的值,如果数据流没有更多数据,则返回 -1。而 Reader 一次返回一个字符,即一个介于 0 和 65535 之间的值,如果数据流没有更多数据,则返回 -1。这并不一定意味着 Reader 每次从所连接的源读取两个字节。它可能一次读取一个或多个字节,这取决于所读取文本的编码。如 UTF-8 编码。
UTF-8 是一种变长字符编码,它可以使用 1 到 4 个字节来表示一个字符。下面为你分别列举一个字节、两个字节、三个字节的 UTF-8 编码示例:
一个字节的 UTF-8 编码用于表示 ASCII 字符,范围是从 U+0000 到 U+007F。最高位为 0,后面 7 位用来表示字符。例如,字符“A”的 ASCII 码是 65,对应的二进制是 01000001,UTF-8 编码下就是一个字节,十六进制为 41。
两个字节的 UTF-8 编码用于表示范围从 U+0080 到 U+07FF 的字符。第一个字节的前两位是 110,第二个字节的前两位是 10。例如,字符“¢”(美分符号)的 Unicode 码点是 U+00A2,对应的二进制是 10100010。在 UTF-8 编码中,它被编码为两个字节,十六进制为 c2a2。
三个字节的 UTF-8 编码用于表示范围从 U+0800 到 U+FFFF 的字符。第一个字节的前三位是 1110,第二个和第三个字节的前两位是 10。例如,字符“中”的 Unicode 码点是 U+4E2D,对应的二进制是 0100111000101101。在 UTF-8 编码中,它被编码为三个字节,十六进制为 e4b8ad。
四个字节的 UTF-8 编码用于表示范围从 U+10000 到 U+10FFFF 的字符,这种字符通常是一些特殊符号、表情符号等。第一个字节的前四位是 11110,后面三个字节的前两位是 10。例如,字符“😀”(笑脸表情)的 Unicode 码点超出了 U+FFFF 范围,需要用四个字节来进行 UTF-8 编码。
Java 中,可以将 Reader 与 InputStream 结合使用。如果你有一个 InputStream 并想从中读取字符,你可以将其封装在一个 InputStreamReader 中。像这样将 InputStream 传递给 InputStreamReader 的构造函数。例如:
package com.hxstrive.java_io.demo01; import java.io.FileInputStream; import java.io.FileReader; import java.io.InputStreamReader; import java.io.Reader; /** * FileReader 示例 * @author hxstrive.com */ public class FileReaderDemo2 { public static void main(String[] args) { // 创建一个 InputStreamReader try(Reader reader = new InputStreamReader( new FileInputStream("C:\\Users\\Administrator\\Desktop\\input.txt"), "UTF-8")) { int data = reader.read(); // 读取数据 while(data != -1){ char dataChar = (char) data; System.out.print(dataChar); data = reader.read(); } } catch (Exception e) { e.printStackTrace(); } } }
上例中,在构造函数中,你还可以指定使用什么字符集来解码文本等,例如:
Java 中,Writer 类是 Java IO API 中所有 Writer 的基类。子类包括 BufferedWriter 和 PrintWriter 等。如下图:
下面是一个简单的 Writer 示例:
package com.hxstrive.java_io.demo01; import java.io.FileWriter; import java.io.Writer; /** * FileWriter 示例 * @author hxstrive.com */ public class FileWriterDemo { public static void main(String[] args) { try(Writer writer = new FileWriter("C:\\Users\\Administrator\\Desktop\\output.txt")) { writer.write("Hello World Writer"); // 将字符串写入到文件 } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
Java 中,Writer 也可以与 OutputStream 结合使用,就像 Readers 和 InputStream 一样。将 OutputStream 包在 OutputStreamWriter 中,写入 Writer 的所有字符都会传递到 OutputStream。下面是一个 OutputStreamWriter 实例:
package com.hxstrive.java_io.demo01; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.io.Writer; /** * FileWriter 示例 * @author hxstrive.com */ public class FileWriterDemo2 { public static void main(String[] args) { try(Writer writer = new OutputStreamWriter( new FileOutputStream("C:\\Users\\Administrator\\Desktop\\output.txt"), "UTF-8")) { writer.write("你好!"); } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
更多 OutputStreamWriter 构造方法,如下图:
与流一样,Reader 和 Writer 可以组合成链,以实现更强大的 IO。其工作原理就像将 Reader 与 InputStream 或 Writer 与 OutputStream 结合在一起一样。
例如,你可以将一个 Reader 封装在一个 BufferedReader 中,或将一个 Writer 封装在一个 BufferedWriter 中,从而实现缓冲功能,提升写入速度:
package com.hxstrive.java_io.demo01; import java.io.*; /** * FileWriter 示例 * @author hxstrive.com */ public class FileWriterDemo3 { public static void main(String[] args) { try(BufferedReader reader = new BufferedReader(new InputStreamReader( new FileInputStream("C:\\Users\\Administrator\\Desktop\\input.txt"), "UTF-8")); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( new FileOutputStream("C:\\Users\\Administrator\\Desktop\\output.txt"), "UTF-8"))) { // 读取文件内容,并写入到输出文件中 String line; while((line = reader.readLine()) != null) { writer.write(line); } } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
关于 Reader 和 Writer,以及他们子类的更多知识请阅读后续章节。