JDK源码-IO系列:缓冲字符流

字符缓冲流

在这里插入图片描述

类关系

结合一句代码了解这个类图

BufferedReader bufferedReader = new BufferedReader(new FileReader(inputFile))

new了一个BufferedReader。输入是一个FileReader。
也就是BufferedReader里面的in变量就是FileReader。
另外几个关联的属性:cb,nchars,nextchar等
看看cb的定义:char cb[],BufferedReader是缓冲字符输入流。cb就是字符缓冲区,默认8192长度。作用是存储一次和操作系统io交互之后,读取到的8192个字符数据。
而nchars的含义是当前cb中的字符总数,nextchar是下一个读取的数据的数组下标。

缓冲区读数据算法

当调用bufferedReader.read()时候看下是怎么工作的

缓冲区字符数组取数据的简单算法描述:
1、当第一次读取一个字符的时候,nextchar =0; nchars=0;这是什么含义,这就是说cb字符数组中没有数据,那就调用FileReader读取一组字符数组到cb中。同时修改nchars=8192;返回cb[extchar++]
2、当读取第二个字符的时候,nextchar=1,nchars=8192。那直接返回cb[nextchar];
3、因为nextchar是从0开始的,当读取完字符缓冲去8192个字符后,下一次读取的时候nextchar=8192。这个时候发现nextchar大于等于nchars=8192;就说明已经读取完缓冲区所有数据了。要重新调用FileReader从操作系统文件中读取下一组数据放到字符缓冲区cb中,并且将nextchar设置为0,nchars=8192;
4、不断往复

FileReader.read()

看上面类图FileReader是InputStreamReader的子类,InputStreamReader有属性sd,就是StreamDecoder。
FileReader.read()调用的是InputStreamReader的read()方法,如下,可以看到实际上调用的是StreamDecoder的read方法。

public int read(char cbuf[], int offset, int length) throws IOException {
        return sd.read(cbuf, offset, length);
    }

StreamDecoder原理

StreamDecoder向上,对FileReader提供了读取字符到字符数组的能力。
向下,面向操作系统文件,通过字节流读取字节数据到ByteBuffer类型的bb属性中。

考虑一个事情:
当我们通过ReadableByteChannel ch读取一次数据,这时候,放入bb缓冲区,bb的大小是8192。
而StreamDecoder面向FileReader提供读取字符的能力,假如一次读取8192个字符到字符数组中。

这个时候,因为ByteBuffer bb中有8192个字节。那是不是8192个字节就能转换为8192个字符返回给FileReader呢?
答案是否定的。

字符包括中英文特殊符号等。比如一个中文UTF_8编码,通常使用3或者4个字节编码。

所以bb中的8192个字节,可能转换成3000+个字符。
这个时候bb缓冲区的数据已经解码完了。
需要继续通过ReadableByteChannel ch继续读取字节数据到bb字节缓冲区。

StreamDecoder读取字符细节

看下StreamDecoder读取内容的方法

int implRead(char[] cbuf, int off, int end) throws IOException 

...
CoderResult cr = decoder.decode(bb, cb, eof);
       if (cr.isUnderflow()) {
            if (eof)
                break;
            if (!cb.hasRemaining())
                break;
            if ((cb.position() > 0) && !inReady())
                break;          // Block at most once
            int n = readBytes();
            if (n < 0) {
                eof = true;
                if ((cb.position() == 0) && (!bb.hasRemaining()))
                    break;
                decoder.reset();
            }
            continue;
        }
        if (cr.isOverflow()) {
            assert cb.position() > 0;
            break;
        }
...

其中decoder是指定或者系统默认的编解码decoder,比如UTF_8
StreamDecoder使用了具体的编解码器对bb的bytebuffer字节数组的字节进行字符编码,并且将编码后的字符写入cb中。

解码CoderResult有两种结果要重点说下:
1、CoderResult的type是CR_UNDERFLOW,代表bb字节中已经读取完了但是还没填充到cb字符数组需要读取的长度,这个时候要继续从FileInputStream中读取8192个字节存储到bb中,进行继续解码
2、CoderResult的type是CR_OVERFLOW,代表解码器decoder解码字节缓冲数组的bb的内容,并切存储到cb字符数组过程中,cb字符数组已经满了,但是字节数组还没有解码完。这个时候记录一下bb字节缓冲数组的,以供下次继续解码。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值