3.1.6 字符流

前面介绍的基本InputStream类和OutputStream类以及包装它们的各种过滤流实现都是在字节层次上操作的。字节流主要由机器来处理。而对于程序的用户来说,他们更愿意看到直接可读的字符。在java.io包中还有一组类用来处理字符流,即java. io.Reader类和java.io.Writer类及其子类。这些字符流处理的是字符类型,而不是字节类型。字符流适合用于处理程序中包含的文本类型的内容。

创建一个字符流的最常见做法是通过一个字节流InputStream类或OutputStream类的对象进行创建,对应的是InputStreamReader类和OutputStreamWriter类。在从字节流转换成字符流时,需要指定字符的编码格式。关于字符的编码和解码,在第4章会有详细的介绍。如果编码格式错误,会产生包含乱码的字符串。在创建InputStreamReader类和OutputStreamWriter类的对象时,总是应该显式地指定一个字符编码格式。如果不指定,使用的是底层Java平台的默认编码格式。这可能造成程序在不同运行平台上的兼容性问题。字符流也可以从String类的对象中创建,即使用java.io.StringReader类和java.io.StringWriter类进行创建;还可以从字符数组中创建,即使用java.io.CharArrayReader类和java.io.CharArrayWriter类进行创建。java.io.BufferedReader类和java.io.BufferedWriter类用来为已有的Reader类和Writer类的对象提供内部缓冲区的支持,以提高读写操作的性能。

在使用字符流处理文本内容时,要注意那些在内容中声明了编码格式的文本格式。这其中最典型的例子是XML文档。XML文档一般通过处理指令来声明其内容的编码格式,如处理指令“<?xml version="1.0"encoding="UTF-8"?>”声明了文档使用的是UTF-8编码格式。当处理指令中不包含编码格式声明时,XML处理器有自己的一套编码格式识别算法。对于这种类型的文档,不应该使用字符流来处理,而是应该使用字节流。使用字节流时不会对原始数据造成影响,能够保证文档处理时的正确性。

在开发中经常会遇到的一个场景是把InputStream类的对象中的内容转换成一个String类的对象。对于这种情况,典型的做法是从InputStream类的对象中创建一个对应的InputStreamReader类的对象,并循环读取到一个char数组中,再把char数组的内容添加到一个java.lang.StringBuilder类的对象中,最后把StringBuilder类的对象转换成一个String类的对象即可。如果希望提高性能,可以使用一个BufferedReader类的对象来包装InputStreamReader类的对象,再调用readLine方法每次读取一行数据。使用java.util.Scanner类也可以完成类似的转换。还可以使用Apache Commons IO库中的org.apache.commons.io.IOUtils类的toString方法。