Java IO:Reader 和 Writer

Java IO 中的 Reader(java.io.Reader)和 Writer(java.io.Writer)类的工作原理与 InputStream 和 OutputStream 非常相似,不同之处在于 Reader 和 Writer 都是基于字符的,用于读写文本。InputStream 和 OutputStream 是基于字节的,还记得吗?

Reader

Java Reader 是 Java IO API 中所有 Reader 的基类。子类包括 BufferedReader、PushbackReader、InputStreamReader、StringReader 等,如下图:

image.png

下面是一个简单的 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 编码。

将 Readers 和 InputStreams 结合

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();
        }
    }

}

上例中,在构造函数中,你还可以指定使用什么字符集来解码文本等,例如:

image.png

Writer

Java 中,Writer 类是 Java IO API 中所有 Writer 的基类。子类包括 BufferedWriter 和 PrintWriter 等。如下图:

image.png

下面是一个简单的 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();
        }
    }

}

运行结果:

d2d780c2c7da4ace2ca63977de88e638_1737015475767-9e0e896d-2cca-4c7d-834f-b4bf1a1da0c0_x-oss-process=image%2Fformat%2Cwebp.png

将 Writers 与 OutputStreams 结合

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();
        }
    }

}

运行结果:

877eed399501d5171df8d1d7b6937962_1737015624372-fbe6806d-0ac1-4739-9190-641b7b47dadc_x-oss-process=image%2Fformat%2Cwebp.png

更多 OutputStreamWriter 构造方法,如下图:

image.png

Readers 和 Writers 结合

与流一样,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();
        }
    }

}

运行结果:

4e4cf6088354561ddcff32d2287e4e05_1737015938165-dc5e9cc7-098f-4c04-8665-6472b0c954b3_x-oss-process=image%2Fformat%2Cwebp.png

关于 Reader 和 Writer,以及他们子类的更多知识请阅读后续章节。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号