字符流的底层也是字节流。字符流=字节流+字符集。
特点是输入流一次读一个字节,遇到中文时,一次读多个字节(读多少个与字符集有关);输出流底层会把数据按照指定的编码方式进行编码,变成字节再写到文件中。
字符流适用于对纯文本文件进行操作。
Reader和Writer是抽象类。
Reader的实现类:
FileReader:操作本地文件的字符输入流;
BufferedReader:操作缓冲区的字符输入流;
LineNumberReader:带有行号的字符输入流。
Writer的实现类:
FileWriter:操作本地文件的字符输出流;
BufferedWriter:操作缓冲区的字符输出流;
LineNumberWriter:带有行号的字符输出流。
一、FileReader
(一)操作步骤
(1)创建字符输入流对象;
(2)读取数据;
(3)释放资源。
注意:
FileReader对象的空参的read()方法默认是“一次读一个字节,遇到中文一次读三个字节”,在读取之后还会进行解码转为十进制,十进制的数字也表示字符集上的数字。例如:英文二进制文件里的数据为“01100001”,read()方法进行读取解码后结果为97;中文二进制文件中内容为“11100110 10110001 10001001”,read()方法进行读取解码转成十进制为27721.
例如,新建一个a.txt文件,内容如下:
强转为字符输出:
带参数的read()读取数据、解码和强转三步合并了,把强转之后的数据放到数组中。
再例如,使用带参数的read():
说明:上述代码,‘害’后面隐藏两个字符"\r\n",所以“害\r”为一组输出,‘\r’没有显示出来;"\n说"为一组输出,且’\n’实现了换行。
注意:上述代码中的细节,new String()指定后面两个参数,读到几个字节就使用几个字节,因为最后可能字节不够填充byte数组。
二、FileWriter
构造方法:
后面两个构造方法第二个参数append赋值为true则进行续写。
成员方法:
例如:
结果为:
FileReader对象通过write()方法把25105根据UTF-8解码规则转化为字符“我”。
再例如,一次写多个字符:
结果为:
注意
基本流(如FileInputStream,FileOutputStream,FilleReader,FileWriter等)不提供显式指定编码的构造函数,它直接使用 Charset.defaultCharset() 解码文件。默认字符集通常继承自:
操作系统区域设置(如中文 Windows 默认是 GBK,Linux/macOS 通常是 UTF-8)。
JVM 启动参数(如 -Dfile.encoding=UTF-8)。
通过 Charset.defaultCharset() 查看当前 JVM 的默认字符集:
System.out.println("Default Charset: " + Charset.defaultCharset().name());
例如,一个文件使用utf-8编码:
使用FileReader进行读取时:
因为默认的解码方式为GBK:
换成GBK编码方法保存即可正常读取:
解决该问题需要使用转换流,见博文《java的转换流、压缩流、序列化流、打印流》。