關于BufferedInputStream的理解

? ? ? ? 在閱讀BufferedInputStream的時候利耍,有些地方有點疑惑蚌本,在研究好久之后,似乎清晰了一點隘梨,在此記錄程癌。

首先,我們來看下這里的主要的成員:

DEFAULT_BUFFER_SIZE = 8912? ?很簡單轴猎,一個默認的buffer大小

MAX_BUFFER_SIZE =?Integer.MAX_VALUE-8; 這個是buffer最大的申請空間嵌莉,這里的-8大概是因為一些虛擬機會在數(shù)組頭部添加一些內容吧。

buf[];? 真正的buffer捻脖,由關鍵字volatile修飾锐峭,表示線程可見。

bufUpdater;一個進行原子操作更新buffer的對象

count? ?這是buffer在流中當前已經讀到的流大小

pos? ?位置可婶,一個在buffer中的位置來標示當前所讀到的位置沿癞。

markpos? ?為了進行重讀流,進行的一個mark標記位置矛渴,在之后執(zhí)行reset()的時候椎扬,pos會回到當前的markpos位置,以用來重復讀取數(shù)據。

mark?的常規(guī)協(xié)定是:如果方法?markSupported?返回?true蚕涤,則輸入流總會在調用?mark?之后記住所有讀取的字節(jié)晶府,并且無論何時調用方法?reset?,都會準備再次提供那些相同的字節(jié)钻趋。但是,如果在調用?reset?之前可以從流中讀取多于?readlimit?的字節(jié)剂习,則根本不需要該流記住任何數(shù)據蛮位。

marklimit? ? 標示在當前的markpos失效之前允許讀到的最大位置。在這里碰到問題鳞绕,為什么會有這個限制呢失仁,通過查詢相關資料我的理解就是當這個值太大的時候,或者pos過大的時候们何,buffer要保存被標記的字節(jié)的話就有些浪費資源萄焦,畢竟buffer是有限的。

接下來看看方法:

getBufIfOpen(): 這個方法用來獲取當前的buffer冤竹,如果buffer關閉拂封,則拋出異常。

構造器:用來創(chuàng)建一個制定大小的buffer字節(jié)數(shù)組鹦蠕。

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



就是檢查當前已讀位置pos和已經讀入的流的大小冒签,來進行讀取數(shù)據,或者是繼續(xù)將流讀入buffer來獲取數(shù)據钟病。因為如果當前的buffer不足達到要讀取的地方萧恕,就會擴展buffer。

在這個方法中肠阱,fill()方法是最主要的一段邏輯票唆。

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



1.當markpos < 0 屹徘,即未被標記走趋,則可以從buffer開頭進行讀入流,之后將流中的內容讀進buffer噪伊,如果buffer空間不足則會進行擴展操作吆视,稍后再提。將count賦值為讀入的字節(jié)大小酥宴。

2.如果當前位置已經達到了buffer的大小(這里我感覺只有=是成立的吧啦吧,有更好的見解請分享給我??),那么進行擴展或者清除動作拙寡。

? 2.1 markpos>0,標示存在mark授滓,就將markpos之后的數(shù)據刷新到buffer的開始。確保mark之后的數(shù)據在以后執(zhí)行reset()的時候可以重讀到。注意般堆,這里只是markpos>0,如果markpos=0,那么就不需要進行被mark的buffer的移位操作在孝。

? 2.2 當markpos=0并且當buffer大小超過了marklimit,(這里可以看到marklimit指的是從開始到pos=marklimit這個位置之間的數(shù)據吧)那么就進行清除標記操作淮摔,以便騰出buffer空間私沮。

? 2.3? buffer大小超過了最大限制,是不允許的操作和橙。

? 2.4? fill()主要是用來填充buffer仔燕,這里就是填充的操作。首先計算一下當前pos有沒有超過buffer最大大小MAX_BUFFER_SIZE的一半魔招,沒有超過就把新的大小nsz設置為pos的二倍晰搀;否則新的大小就是MAX_BUFFER_SIZE。然后比較nsz有沒有超過marklimit办斑,超過了就重新設置成marklimit的大型馑 (在這里發(fā)現(xiàn),這樣做的目的是要控制buffer大小乡翅,不要超過marklimit鳞疲,否則之后進行reset()的時候,會發(fā)現(xiàn)mark被清除導致異常發(fā)生蠕蚜。)然后進行一次buffer的擴展建丧,將當前位置pos之前的數(shù)據拷貝到增大容量后的buffer。之后的updater.compareAndSet()是做什么用的呢波势?如果說是拷貝數(shù)據那么前一句話的拷貝是做什么用的翎朱?

通過在此分析發(fā)現(xiàn),前面的拷貝操作只是將數(shù)據賦值給新的nbuf尺铣,并沒有刷新對象本身的buffer拴曲,這個就是利用原子操作來進行這個動作確保原數(shù)組引用指向新數(shù)據。


看一下read1()和read()






從read方法的循環(huán)中凛忿,可以看到nread = read1(b, off + n, len - n),再去read1中觀察澈灼,

計算還有多少可讀avail,如果不夠店溢,那么先檢查叁熔,如果markpos存在,同時要讀的大小超過了buffer大小床牧,那么就進行read()荣回。這兩個部分實現(xiàn)了縮小讀取范圍,直到len小于buffer的大小戈咳,那么就可以進行buffer的填充了心软,填充過后重新計算avail壕吹,重新計算讀取的范圍將buffer數(shù)據讀入拷貝到接受流b中,如果inputStream中沒有可用數(shù)據進行讀取删铃,那么就返回耳贬。

read()是貪婪讀取,即從buffer中不斷獲取數(shù)據猎唁,buffer不斷填充咒劲,直到inputStream沒有可讀數(shù)據。read1()是非貪婪的诫隅,只會讀到buffer的結束腐魂,這兩個方法組合使用來達到從inputStream中獲取足夠多的數(shù)據。


skip()



如果可讀數(shù)據不足阎肝,沒有mark的情況下直接從流inputStream中跳過;如果標記了mark肮街,那么先填充风题,重新計算avail,進行pos的跳躍操作嫉父。

close()



利用原子操作把buffer進行指向null沛硅,inputStream指向null并且關閉對應的流來實現(xiàn)對整個資源的釋放。

以上就是一些主要方法的理解绕辖,還有幾個問題摇肌,希望大家?guī)兔μ崾疽恍〇|西。


注:這里的mark是為了實現(xiàn)對流的重讀仪际,假如沒有標記围小,那么可以隨意操作。反之树碱,我們需要保證流的重讀性肯适,一些數(shù)據的重復獲取還是很重要的,除非被重讀標記的范圍marklimit過大占用太多的資源成榜,得不償失框舔,所以進行了標記復位操作來釋放一些資源。

BufferedInputStream主要是用于進行針對磁盤io或是其他設備來優(yōu)化的赎婚,用來提高效率刘绣,并且減少讀取次數(shù)可以減少設備的損耗。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末挣输,一起剝皮案震驚了整個濱河市纬凤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌撩嚼,老刑警劉巖移斩,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肚医,死亡現(xiàn)場離奇詭異,居然都是意外死亡向瓷,警方通過查閱死者的電腦和手機肠套,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來猖任,“玉大人你稚,你說我怎么就攤上這事≈焯桑” “怎么了刁赖?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長长搀。 經常有香客問我宇弛,道長,這世上最難降的妖魔是什么源请? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任枪芒,我火速辦了婚禮,結果婚禮上谁尸,老公的妹妹穿的比我還像新娘舅踪。我一直安慰自己,他們只是感情好良蛮,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布抽碌。 她就那樣靜靜地躺著,像睡著了一般决瞳。 火紅的嫁衣襯著肌膚如雪货徙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天皮胡,我揣著相機與錄音破婆,去河邊找鬼。 笑死胸囱,一個胖子當著我的面吹牛祷舀,可吹牛的內容都是我干的。 我是一名探鬼主播烹笔,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼裳扯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谤职?” 一聲冷哼從身側響起饰豺,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎允蜈,沒想到半個月后冤吨,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蒿柳,經...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年漩蟆,在試婚紗的時候發(fā)現(xiàn)自己被綠了垒探。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡怠李,死狀恐怖圾叼,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情捺癞,我是刑警寧澤夷蚊,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站髓介,受9級特大地震影響惕鼓,放射性物質發(fā)生泄漏。R本人自食惡果不足惜唐础,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一箱歧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧彻犁,春花似錦叫胁、人聲如沸凰慈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽微谓。三九已至森篷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間豺型,已是汗流浹背仲智。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留姻氨,地道東北人钓辆。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像肴焊,于是被迫代替她去往敵國和親前联。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內容