java的字符流被设定为对文件内部的数据进行读写操作的一组对象。
字符流和字节流的使用有很相似的地方,但字符流更针对文本文件的操作,因为他可以直接读取字符串。
学习字符流的具体使用之间,需要知道一点编码与解码的知识:
编码与解码
编码:就是将人类语言文字转换成二进制数据
解码:将二进制数据转化为人类语言文字。
所以这是一个相互作用的过程,当我们想要将数据,文件保存在计算机上,就必须考虑如何进行编解码。而且编解码不一致会产生错误,导致文件乱码。所以编解码应当使用同一套字符集(编解码表)。目前常用的编解码表为:
windows: GBK
idea等编译器工具: utf-8
java中的编解码方式
以字符串的转化为例:
字符串-->byte字节数组
str.getBytes()
,返回值是一个字节数组
str.getBytes(String charsetName)
,返回值是一个以charsetName编码表编码的字节数组
byte字节数组--> 字符串
new String(byte[] bytes)
,本质上是调用了String的构造方法,返回值是一个字符串
new String(byte[] bytes, String charsetName)
, 返回值是一个以charsetName编码表解码的字符串。
java中处理流的四种抽象基类
OutputStream:
InputStream
Writer
Reader
其中Writer和Reader两个抽象类专门用来处理字符,而OutputStream和InputStream用来处理字节流,更具有通用性。他们还有各种子类来实现不同的功能,常用的几个子类的继承关系如图:
可以看到
共性1:四个抽象基类都实现了Closeable接口,实现了close()方法。这是因为他们都调用了jvm之外的系统资源(文件),每次对外部资源的使用都需要归还。
共性2:负责输出(比如将数据写入硬盘具体文件)的两个抽象基类都实现了Flushable接口, 调用flush方法是为了将任何缓冲的输出写入底层流。大多数情况下,这里的写入底层流都是指将缓冲区的数据写入外部资源(文件,网络)。
Writer的几个具体子类
Writer的几个具体子类有转换流(OutputStreamWriter),简化流(FileWriter)和缓冲流(BufferedWriter)。他们都实现了抽象父类Writer的write()方法,可以直接向文件输出字符串。
转换流(OutputStreamWriter)是一个包装流,他包装了一个OutStream流对象,使得可以在输出字节的基础上直接实现输出字符串的功能,方便写代码。而且可以在构造该对象时指定编码字符集。
简化流(FileWriter)在OutputStreamWriter的基础上进一步封装,是他的直接子类。不在需要指定OutStream对象,而是直接指定File对象即可创建一个简化流对象。这体现在他的构造器中。
而OutputStream类的构造器还需要指定输出流对象。
但简化流不能指定字符集,只能用当前操作平台的默认字符集进行编码。
当追求大文件读写速度时,Writer还有一个子类BufferedWriter缓冲流,自带默认大小为16KB的缓冲区,也可以在创建对象时指定缓冲区大小。缓冲流有自己独有的newLine()方法,可以向文件写入一个适配系统的换行。
Reader的几个具体子类
Reader的几个具体子类有转换流(InputStreamReader),简化流(FileReader)和缓冲流(BufferedReader)。他们都实现了抽象父类Reader的read()方法,可以读入单个字符,或者一次性读入一个字符数组。
转换流(InputStreamReader)是一个包装流,具体功能和他相对应的另一个负责输出的转换流一样。只不过成员方法是read方法。他也可以指定字符集,就是在构造时需要传入一个InputStream对象。
简化流(FileReader)在转换流的基础上进一步封装,是他的直接子类。只需要在构造时指定一个File对象。或者更简单的,指定一个文件名字符串就可以!真是名副其实的一个类!这体现在他的构造方法上:
缓冲流(BufferedReader)自带缓冲区,适合大文件读写,可以指定缓冲区大小,有自己独有的readLine()方法,可以一次性读取文件的一行数据,并返回该行形成的字符串。如果读到文件末尾,返回null。
需要注意的是,缓冲流也是一个包装流,在构造时需要传入一个Reader对象作为底层流,我们直接传入一个FileReader对象是最简单的方法!
原文:https://juejin.cn/post/7102797053155082248