IO-------转换流
转换流:
·InputStreamReader:将字节流转换为字符流
·OutputStreamWriter:将字符流转换为字节流
·使用场景:
|-- 源或者目的对应的设备是字节流,但是操作的却是文本数据,可以使用转换作为桥梁。
|-- 提高对文本操作的效率
·一旦操作文本涉及到具体的指定编码表时,必须使用转换流。
一、InputStreamReader的简单使用
public static void inputStreamReader() throws IOException {
// 字节流输入,手动输入内容
InputStream is = System.in;
// 创建使用默认编码表的 InputStreamReader,isr现在已经是字符流了
InputStreamReader isr = new InputStreamReader(is);
// 获取当前流使用的编码表名称
System.out.println(isr.getEncoding());
// 字符流输出
BufferedReader br = new BufferedReader(isr);
// 按行读取
String line;
while ((line = br.readLine()) != null) {
if ("over".equals(line)) {
break;
}
System.out.println(line);
}
br.close();
isr.close();
}
二、OutputStreamWriter的简单使用
“`
public static void outputStreamWriter() throws IOException {
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
// 创建使用默认字符编码的OutputStreamWriter
OutputStreamWriter osw = new OutputStreamWriter(System.out);
// 获取当前流使用的编码表的名称
System.out.println(osw.getEncoding());
BufferedWriter bufw = new BufferedWriter(osw);
String line;
while ((line = bufr.readLine()) != null) {
if ("over".equals(line)) {
break;
}
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufr.close();
bufw.close();
}
三、源码剖析转换流
一、InputStreamReader
1.继承关系:
|-java.lang.Object
|---java.io.Reader
|---java.io.InputStreamReader
直接已知子类:FileReader
2.基本属性:private final StreamDecoder sd;
3.构造方法:
·InputStreamReader(InputStream in)
|-创建使用默认编码表的 InputStreamReader。
·InputStreamReader(InputStream in, Charset cs)
|-创建使用给定编码表的 InputStreamReader。
·InputStreamReader(InputStream in, CharsetDecoder dec)
|-创建使用给定编码表解码器的 InputStreamReader。
·InputStreamReader(InputStream in, String charsetName)
|-创建使用指定编码表的 InputStreamReader。
4.方法:
·close() 关闭该流并释放与之关联的所有资源。
·getEncoding() 返回此流使用的字符编码的名称。
·read() 读取单个字符。
·read(char[] cbuf, int offset, int length) 将字符读入数组中的某一部分。
·ready()判断此流是否已经准备好用于读取
源码分析:以InputStreamReader(InputStream in, String charsetName)为例:
属性StreamDecoder sd:每个构造函数都通过该属性确定要选用的编码表
看StreamDecoder类:Reader的实现类,在包sun.nio.cs中,这个包的具体位置是
www.docjar.com/html/api/sun/nio/cs/StreamEncoder.java.html
在StreamDecoder类中有forInputStreamReader方法:
当本系统支持该编码表时调用StreamDecoder(参数不定),并传入了指定的编码表:
其中onMalformedInput(CodingErrorAction.REPLACE)方法是为了更改此解码器针对格式错误输入错误的操作。
onUnmappableCharacter(CodingErrorAction.REPLACE)方法是为了更改此解码器对不可映射字符错误的操作。
即此时指定编码表的解码器已经避免了在解码过程中可能出现的错误。
再看通过this调用的方法:
ReadableByteChannel型的参数ch的作用是从指定通道读取一个字节序列到给定的缓冲区。这是转换流中很重要的一步。
看allocate方法:
通过HeapByteBuffer方法,将jvm堆上所维护的byte[]拷贝至堆外内存,然后堆外内存直接和io设备交互,即将数据缓存到byteBuffer中。
再看flip方法:
flip()方法涉及到buffer中的Capacity,Position和Limit三个属性。
其中capacity在读写模式下都是固定的,就是我们分配的缓冲大小,position类似于读写指针,表示当前读(写)到什么位置,limit在写模式下表示最多能写入多少数据,此时和capacity相同,在读模式下表示最多能读多少数据,此时和缓存中的实际数据大小相同。
在写模式下调用flip方法,那么limit就设置为了position当前的值(即当前写了多少数据),postion会被置为0,以表示读操作从缓存的头开始读。也就是说调用flip之后,读写指针指到缓存头部,并且设置了最多只能读出之前写入的数据长度(而不是整个缓存的容量大小)。
关于flip()方法可以看看这篇文章:https://blog.csdn.net/u013096088/article/details/78638245
即flip()方法将byteBuffer中的字节数据每次按照limit的长度取出,也就在这一步实现了由字节到字符的转换。
二、OutputStreamWriter
1.继承关系:
|-java.lang.Object
|---java.io.Writer
|---java.io.OutputStreamReader
2.属性:private final StreamEncoder se;
3.构造方法:
·OutputStreamWriter(OutputStream out)
|-创建使用默认字符编码的 OutputStreamWriter
·OutputStreamWriter(OutputStream out, Charset cs)
|-创建使用给定字符集的 OutputStreamWriter
·OutputStreamWriter(OutputStream out, CharsetEncoder enc)
|-创建使用给定字符集编码器的 OutputStreamWriter
·OutputStreamWriter(OutputStream out, String charsetName)
|-创建使用指定字符集的 OutputStreamWriter
4.方法
·close() 关闭此流,但要先刷新它。
·flush() 刷新该流的缓冲。
·getEncoding() 返回此流使用的字符编码的名称。
·write(char[] cbuf, int off, int len) 写入字符数组的某一部分。
·write(int c) 写入单个字符。
·write(String str, int off, int len) 写入字符串的某一部分。
源码分析:以OutputStreamWriter(OutputStream out, String charsetName)为例:
直接从StreamDecoder类的forOutputStreamReader方法开始:
如果指定的编码表为null,则使用默认的。
不为空,如果系统支持该编码表,调用StreamEncoder方法:
与上面类似,再看this调用的方法:
在这一步,有WritableByteChannel型的参数ch,WritableByteChannel类是只允许写入字节的通道,即从byteBuffer中每次只能读取到一个字节,所以这是字符流转化为字节流的关键
上一篇: IO分类