关于BufferedInputStream的理解

        在阅读BufferedInputStream的时候,有些地方有点疑惑,在研究好久之后,似乎清晰了一点,在此记录。

首先,我们来看下这里的主要的成员:

DEFAULT_BUFFER_SIZE = 8912   很简单,一个默认的buffer大小

MAX_BUFFER_SIZE = Integer.MAX_VALUE-8; 这个是buffer最大的申请空间,这里的-8大概是因为一些虚拟机会在数组头部添加一些内容吧。

buf[];  真正的buffer,由关键字volatile修饰,表示线程可见。

bufUpdater;一个进行原子操作更新buffer的对象

count   这是buffer在流中当前已经读到的流大小

pos   位置,一个在buffer中的位置来标示当前所读到的位置。

markpos   为了进行重读流,进行的一个mark标记位置,在之后执行reset()的时候,pos会回到当前的markpos位置,以用来重复读取数据。

mark 的常规协定是:如果方法 markSupported 返回 true,则输入流总会在调用 mark 之后记住所有读取的字节,并且无论何时调用方法 reset ,都会准备再次提供那些相同的字节。但是,如果在调用 reset 之前可以从流中读取多于 readlimit 的字节,则根本不需要该流记住任何数据。

marklimit    标示在当前的markpos失效之前允许读到的最大位置。在这里碰到问题,为什么会有这个限制呢,通过查询相关资料我的理解就是当这个值太大的时候,或者pos过大的时候,buffer要保存被标记的字节的话就有些浪费资源,毕竟buffer是有限的。

接下来看看方法:

getBufIfOpen(): 这个方法用来获取当前的buffer,如果buffer关闭,则抛出异常。

构造器:用来创建一个制定大小的buffer字节数组。

在inputStream中主要的使用方法就是read(), 这里的这个方法



就是检查当前已读位置pos和已经读入的流的大小,来进行读取数据,或者是继续将流读入buffer来获取数据。因为如果当前的buffer不足达到要读取的地方,就会扩展buffer。

在这个方法中,fill()方法是最主要的一段逻辑。

下面解读一下fill()的目的。



1.当markpos < 0 ,即未被标记,则可以从buffer开头进行读入流,之后将流中的内容读进buffer,如果buffer空间不足则会进行扩展操作,稍后再提。将count赋值为读入的字节大小。

2.如果当前位置已经达到了buffer的大小(这里我感觉只有=是成立的吧,有更好的见解请分享给我😁),那么进行扩展或者清除动作。

  2.1 markpos>0,标示存在mark,就将markpos之后的数据刷新到buffer的开始。确保mark之后的数据在以后执行reset()的时候可以重读到。注意,这里只是markpos>0,如果markpos=0,那么就不需要进行被mark的buffer的移位操作。

  2.2 当markpos=0并且当buffer大小超过了marklimit,(这里可以看到marklimit指的是从开始到pos=marklimit这个位置之间的数据吧)那么就进行清除标记操作,以便腾出buffer空间。

  2.3  buffer大小超过了最大限制,是不允许的操作。

  2.4  fill()主要是用来填充buffer,这里就是填充的操作。首先计算一下当前pos有没有超过buffer最大大小MAX_BUFFER_SIZE的一半,没有超过就把新的大小nsz设置为pos的二倍;否则新的大小就是MAX_BUFFER_SIZE。然后比较nsz有没有超过marklimit,超过了就重新设置成marklimit的大小(在这里发现,这样做的目的是要控制buffer大小,不要超过marklimit,否则之后进行reset()的时候,会发现mark被清除导致异常发生。)然后进行一次buffer的扩展,将当前位置pos之前的数据拷贝到增大容量后的buffer。之后的updater.compareAndSet()是做什么用的呢?如果说是拷贝数据那么前一句话的拷贝是做什么用的?

通过在此分析发现,前面的拷贝操作只是将数据赋值给新的nbuf,并没有刷新对象本身的buffer,这个就是利用原子操作来进行这个动作确保原数组引用指向新数据。


看一下read1()和read()






从read方法的循环中,可以看到nread = read1(b, off + n, len - n),再去read1中观察,

计算还有多少可读avail,如果不够,那么先检查,如果markpos存在,同时要读的大小超过了buffer大小,那么就进行read()。这两个部分实现了缩小读取范围,直到len小于buffer的大小,那么就可以进行buffer的填充了,填充过后重新计算avail,重新计算读取的范围将buffer数据读入拷贝到接受流b中,如果inputStream中没有可用数据进行读取,那么就返回。

read()是贪婪读取,即从buffer中不断获取数据,buffer不断填充,直到inputStream没有可读数据。read1()是非贪婪的,只会读到buffer的结束,这两个方法组合使用来达到从inputStream中获取足够多的数据。


skip()



如果可读数据不足,没有mark的情况下直接从流inputStream中跳过;如果标记了mark,那么先填充,重新计算avail,进行pos的跳跃操作。

close()



利用原子操作把buffer进行指向null,inputStream指向null并且关闭对应的流来实现对整个资源的释放。

以上就是一些主要方法的理解,还有几个问题,希望大家帮忙提示一些东西。


注:这里的mark是为了实现对流的重读,假如没有标记,那么可以随意操作。反之,我们需要保证流的重读性,一些数据的重复获取还是很重要的,除非被重读标记的范围marklimit过大占用太多的资源,得不偿失,所以进行了标记复位操作来释放一些资源。

BufferedInputStream主要是用于进行针对磁盘io或是其他设备来优化的,用来提高效率,并且减少读取次数可以减少设备的损耗。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容