以下内容介绍reader和writer的简单使用...后续遇到好的程序会不断更新
Reader
Reader
是Java的IO库提供的另一个输入流接口。和
InputStream
的区别是,
InputStream
是一个字节流,即以
byte
为单位读取,而
Reader
是一个字符流,即以
char
为单位读取:
FileReader
FileReader
是
Reader
的一个子类,它可以打开文件并获取
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
}
一次性读取若干字符
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(实现从字节流到字符流的转换)
Reader
本质上是一个基于
InputStream
的
byte
到
char
的转换器,那么,如果我们已经有一个
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
时,它会在内部自动调用
InputStream
的
close()
方法,所以,只需要关闭最外层的
Reader
对象即可。
Writer
Writer
和
OutputStream
的区别如下:
FileWriter
FileWriter
就是向文件中写入字符流的
Writer
。它的使用方法和
FileReader
类似:
try (Writer writer = new FileWriter("readme.txt", StandardCharsets.UTF_8)) {
writer.write('H'); // 写入单个字符
writer.write("Hello".toCharArray()); // 写入char[]
writer.write("Hello"); // 写入String
}
CharArrayWriter
CharArrayWriter
可以在内存中创建一个
Writer
,它的作用实际上是构造一个缓冲区,可以写入
char
,最后得到写入的
char[]
数组,这和
ByteArrayOutputStream
非常类似
try (CharArrayWriter writer = new CharArrayWriter()) {
writer.write(65);
writer.write(66);
writer.write(67);
char[] data = writer.toCharArray(); // { 'A', 'B', 'C' }
}
StringWriter
StringWriter
也是一个基于内存的
Writer
,它和
CharArrayWriter
类似。实际上,
StringWriter
在内部维护了一个
StringBuffer
,并对外提供了
Writer
接口。
OutputStreamWriter
除了
CharArrayWriter
和
StringWriter
外,普通的Writer实际上是基于
OutputStream
构造的,它接收
char
,然后在内部自动转换成一个或多个
byte
,并写入
OutputStream
。因此,
OutputStreamWriter
就是一个将任意的
OutputStream
转换为
Writer
的转换器:
try (Writer writer = new OutputStreamWriter(new FileOutputStream("readme.txt"), "UTF-8")) {
// TODO:
}
上述代码实际上就是
FileWriter
的一种实现方式。