阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Reader

35次阅读
没有评论

共计 2757 个字符,预计需要花费 7 分钟才能阅读完成。

Reader是 Java 的 IO 库提供的另一个输入流接口。和 InputStream 的区别是,InputStream是一个字节流,即以 byte 为单位读取,而 Reader 是一个字符流,即以 char 为单位读取:

InputStream Reader
字节流,以 byte 为单位 字符流,以 char 为单位
读取字节(-1,0~255):int read() 读取字符(-1,0~65535):int read()
读到字节数组:int read(byte[] b) 读到字符数组:int read(char[] c)

java.io.Reader是所有字符输入流的超类,它最主要的方法是:

public int read() throws IOException;

这个方法读取字符流的下一个字符,并返回字符表示的int,范围是0~65535。如果已读到末尾,返回-1

FileReader

FileReaderReader 的一个子类,它可以打开文件并获取 Reader。下面的代码演示了如何完整地读取一个FileReader 的所有字符:

public void readFile() throws IOException {// 创建一个 FileReader 对象:
    Reader reader = new FileReader("src/readme.txt"); // 字符编码是???
    for (;;) {int n = reader.read(); // 反复调用 read()方法,直到返回 -1
        if (n == -1) {break;
        }
        System.out.println((char)n); // 打印 char
    }
    reader.close(); // 关闭流
}

如果我们读取一个纯 ASCII 编码的文本文件,上述代码工作是没有问题的。但如果文件中包含中文,就会出现乱码,因为 FileReader 默认的编码与系统相关,例如,Windows 系统的默认编码可能是 GBK,打开一个UTF-8 编码的文本文件就会出现乱码。

要避免乱码问题,我们需要在创建 FileReader 时指定编码:

Reader reader = new FileReader("src/readme.txt", StandardCharsets.UTF_8);

InputStream 类似,Reader也是一种资源,需要保证出错的时候也能正确关闭,所以我们需要用 try (resource) 来保证 Reader 在无论有没有 IO 错误的时候都能够正确地关闭:

try (Reader reader = new FileReader("src/readme.txt", StandardCharsets.UTF_8)) {// TODO
}

Reader还提供了一次性读取若干字符并填充到 char[] 数组的方法:

public int read(char[] c) throws IOException

它返回实际读入的字符个数,最大不超过 char[] 数组的长度。返回 -1 表示流结束。

利用这个方法,我们可以先设置一个缓冲区,然后,每次尽可能地填充缓冲区:

public void readFile() throws IOException {try (Reader reader = new FileReader("src/readme.txt", StandardCharsets.UTF_8)) {char[] buffer = new char[1000];
        int n;
        while ((n = reader.read(buffer)) != -1) {System.out.println("read" + n + "chars.");
        }
    }
}

CharArrayReader

CharArrayReader可以在内存中模拟一个 Reader,它的作用实际上是把一个char[] 数组变成一个 Reader,这和ByteArrayInputStream 非常类似:

try (Reader reader = new CharArrayReader("Hello".toCharArray())) {
}

StringReader

StringReader可以直接把 String 作为数据源,它和 CharArrayReader 几乎一样:

try (Reader reader = new StringReader("Hello")) {
}

InputStreamReader

ReaderInputStream 有什么关系?

除了特殊的 CharArrayReaderStringReader,普通的 Reader 实际上是基于 InputStream 构造的,因为 Reader 需要从 InputStream 中读入字节流(byte),然后,根据编码设置,再转换为 char 就可以实现字符流。如果我们查看 FileReader 的源码,它在内部实际上持有一个FileInputStream

既然 Reader 本质上是一个基于 InputStreambytechar 的转换器,那么,如果我们已经有一个 InputStream,想把它转换为Reader,是完全可行的。InputStreamReader 就是这样一个转换器,它可以把任何 InputStream 转换为Reader。示例代码如下:

// 持有 InputStream:
InputStream input = new FileInputStream("src/readme.txt");
// 变换为 Reader:
Reader reader = new InputStreamReader(input, "UTF-8");

构造 InputStreamReader 时,我们需要传入 InputStream,还需要指定编码,就可以得到一个Reader 对象。上述代码可以通过 try (resource) 更简洁地改写如下:

try (Reader reader = new InputStreamReader(new FileInputStream("src/readme.txt"), "UTF-8")) {// TODO:
}

上述代码实际上就是 FileReader 的一种实现方式。

使用 try (resource) 结构时,当我们关闭 Reader 时,它会在内部自动调用 InputStreamclose()方法,所以,只需要关闭最外层的 Reader 对象即可。

提示

使用 InputStreamReader,可以把一个 InputStream 转换成一个 Reader。

小结

Reader定义了所有字符输入流的超类:

  • FileReader实现了文件字符流输入,使用时需要指定编码;
  • CharArrayReaderStringReader 可以在内存中模拟一个字符流输入。

Reader是基于 InputStream 构造的:可以通过 InputStreamReader 在指定编码的同时将任何 InputStream 转换为Reader

总是使用 try (resource) 保证 Reader 正确关闭。

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-08-05发表,共计2757字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中