字节流与字符流之间的区别却可以联系起来,这就是表中的两个类InputStreamReader和OutputStreamWriter。InputStreamReader负责把字节输入流转换为字符输入流,OutputStreamWriter负责把输出字节流转换为输出字符流。下面来看看如何进行转换。
1.字节输入流转换为字符输入流
InputStreamReader是字节流通向字符流的桥梁,它使用指定的charset读取字节并将其解码为字符。它拥有一个InputStream类型的变量,并继承了Reader,使用了对象的适配器模式,如图12-9所示。
根据InputStream的实例创建InputStreamReader的方法有4种:
- InputStreamReader(InputStream in);
- //根据默认字符集创建
- InputStreamReader(InputStream in, Charset cs);
- //使用给定字符集创建
- InputStreamReader(InputStream in, CharsetDecoder dec);
- //使用给定字符集解码器创建
- InputStreamReader(InputStream in, String charsetName);
- //使用指定字符集创建
后面的3个构造函数都指定了一个字符集,最后一个是最简单的,可以直接指定字符集的名称来创建,例如GB2312等。
每次调用InputStreamReader中的一个read()方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。共有3个可用的read()方法:
- int read();
- //读取单个字符
- int read(char[] cbuf, int offset, int length);
- //将字符读入数组中的某一部分
- boolean ready();
- //判断此流是否已经准备好用于读取
InputStreamReader继承自Reader,因此该类的实例可以被各种输入字符流包装。为了达到最高效率,可以考虑在BufferedReader内包装InputStreamReader。例如程序12-20所示,我们首先创建了一个FileInputStream类的实例,然后转换为InputStreamReader对象is,最后使用BufferedReader进行包装。这样就可以将字节流转换为带缓冲功能的字符流。
程序12-20 TestInputStreamReader.java
- public class TestInputStreamReader {
- public static void main(String[] args) {
- try {
- // 创建输入流
- FileInputStream fis = new FileInputStream("D:/demo/test.txt");
- InputStreamReader is = new InputStreamReader(fis);
- BufferedReader bis = new BufferedReader(is);
-
- // 从输入流读取数据
- while (bis.ready()) {
- int c = bis.read();
- System.out.print((char)c);
- }
-
- // 关闭输入流
- bis.close();
- is.close();
- fis.close();
- } catch (IOException e) {
- }
- }
- }
2.字节输出流转换为字符输出流
OutputStreamWriter是字符流通向字节流的桥梁,可使用指定的charset将要写入流中的字符编码成字节。因此,它拥有一个OutputStream类型的变量,并继承了Writer,使用了对象的适配器模式,如图12-10所示。
根据OutputStream的实例创建OutputStreamWriter的方法有4种:
- OutputStreamReader(OutputStream out);
- //根据默认字符集创建
- OutputStreamReader(OutputStream out, Charset cs);
- //使用给定字符集创建
- OutputStreamReader(OutputStream out, CharsetDecoder dec);
- //使用给定字符集解码器创建
- OutputStreamReader(OutputStream out, Stroutg charsetName);
- //使用指定字符集创建
后面的3个构造函数都制定了一个字符集,最后一个是最简单的,可以直接指定字符集的名称来创建,例如GB2312等。
每次调用write()方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递给write()方法的字符没有缓冲。共有3个可用的write()方法:
- void write(char[] cbuf, int off, int len);//写入字符数组的某一部分
- void write(int c);//写入单个字符
- void write(String str, int off, int len);//写入字符串的某一部分
OutputStreamWriter继承自Writer,因此该类的实例可以被各种输出字符流包装。为了达到最高效率,可以考虑在BufferedWriter内包装OutputStreamWriter。例如程序12-21所示,我们首先创建了一个FileOutputStream类的实例,然后转换为OutputStreamReader对象os,最后使用BufferedWriter进行包装。这样就可以将字节流转换为带缓冲功能的字符流。
程序12-21 TestOutputStreamWriter.java
- public class TestOutputStreamWriter {
- public static void main(String[] args) {
- try {
- // 创建输出流
- FileOutputStream fos = new FileOutputStream("D:/demo/test.txt");
- OutputStreamWriter os = new OutputStreamWriter(fos);
- BufferedWriter bos = new BufferedWriter(os);
-
- // 写入数组数据
- char[] buf = new char[3];
- buf[0] = 'a';
- buf[1] = 'b';
- buf[2] = '中';
- bos.write(buf);
-
- // 关闭输出流
- bos.close();
- os.close();
- fos.close();
- } catch (IOException e) {
- }
- }
- }