日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

BufferedInputStream学习笔记

發(fā)布時(shí)間:2023/12/10 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BufferedInputStream学习笔记 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

【本文轉(zhuǎn)載于http://icanfly.iteye.com/blog/1207397】


BufferedInputStream是一個(gè)帶有緩沖區(qū)域的InputStream,它的繼承體系如下:?

InputStream?
|__FilterInputStream?
??????? |__BufferedInputStream
?

首先了解一下FilterInputStream:?
FilterInputStream通過裝飾器模式將InputStream封裝至內(nèi)部的一個(gè)成員變量:?
Java代碼??
  • protected?volatile?InputStream?in;??

  • 需要注意的是該成員變量使用了volatile關(guān)鍵字進(jìn)行修飾,這意味著該成員變量的引用的內(nèi)存可見性為多線程即時(shí)可見的。?
    其它地方FilterInputStream將所有的操作委托給了in這個(gè)成員進(jìn)行操作。?

    了解了這些過后,來仔細(xì)看看BufferedInputStream的成員變量:?
    Java代碼??
  • private?static?int?defaultBufferSize?=?8192?//該變量定義了默認(rèn)的緩沖大小??
  • ??
  • protected?volatile?byte?buf[];?//緩沖數(shù)組,注意該成員變量同樣使用了volatile關(guān)鍵字進(jìn)行修飾,作用為在多線程環(huán)境中,當(dāng)對(duì)該變量引用進(jìn)行修改時(shí)保證了內(nèi)存的可見性。??
  • ??
  • private?static?final?AtomicReferenceFieldUpdater<BufferedInputStream,?byte[]>?bufUpdater?=?AtomicReferenceFieldUpdater.newUpdater(BufferedInputStream.class,??byte[].class,?"buf")//緩存數(shù)組的原子更新器,該成員變量與buf數(shù)組的volatile關(guān)鍵字共同組成了buf數(shù)組的原子更新功能實(shí)現(xiàn)。??
  • ??
  • protected?int?count;//該成員變量表示目前緩沖區(qū)域中有多少有效的字節(jié)。??
  • ??
  • protected?int?pos;//該成員變量表示了當(dāng)前緩沖區(qū)的讀取位置。??
  • ??
  • protected?int?markpos?=?-1;/*表示標(biāo)記位置,該標(biāo)記位置的作用為:實(shí)現(xiàn)流的標(biāo)記特性,即流的某個(gè)位置可以被設(shè)置為標(biāo)記,允許通過設(shè)置reset(),將流的讀取位置進(jìn)行重置到該標(biāo)記位置,但是InputStream注釋上明確表示,該流不會(huì)無(wú)限的保證標(biāo)記長(zhǎng)度可以無(wú)限延長(zhǎng),即markpos=15,pos=139734,該保留區(qū)間可能已經(jīng)超過了保留的極限(如下)*/??
  • ??
  • protected?int?marklimit;/*該成員變量表示了上面提到的標(biāo)記最大保留區(qū)間大小,當(dāng)pos-markpos>?marklimit時(shí),mark標(biāo)記可能會(huì)被清除(根據(jù)實(shí)現(xiàn)確定)。*/??



  • 通過構(gòu)造函數(shù)可以看到:初始化了一個(gè)byte數(shù)組作為緩沖區(qū)域?
    Java代碼??
  • public?BufferedInputStream(InputStream?in,?int?size)?{??
  • ????super(in);??
  • ????????if?(size?<=?0)?{??
  • ????????????throw?new?IllegalArgumentException("Buffer?size?<=?0");??
  • ????????}??
  • ????buf?=?new?byte[size];??
  • }??



  • 這個(gè)類中最為重要的方法是fill()方法,它提供了緩沖區(qū)域的讀取、寫入、區(qū)域元素的移動(dòng)更新等。下面著重分析一下該方法:?
    Java代碼??
  • private?void?fill()?throws?IOException?{??
  • ????????byte[]?buffer?=?getBufIfOpen();??
  • ????if?(markpos?<?0)?{??
  • ??????????/*如果不存在標(biāo)記位置(即沒有需要進(jìn)行reset的位置需求)?
  • ????????????則可以進(jìn)行大膽地直接重置pos標(biāo)識(shí)下一可讀取位置,但是這樣?
  • ????????????不是會(huì)讀取到以前的舊數(shù)據(jù)嗎?不用擔(dān)心,在后面的代碼里會(huì)實(shí)現(xiàn)輸入流的新??
  • ????????????數(shù)據(jù)填充*/??
  • ????????pos?=?0;??????????
  • ????}else?if?(pos?>=?buffer.length){??
  • ???????/*?位置大于緩沖區(qū)長(zhǎng)度,這里表示已經(jīng)沒有可用空間了?*/??
  • ????????if?(markpos?>?0)?{?????
  • ?????????????/*?表示存在mark位置,則要對(duì)mark位置到pos位置的數(shù)據(jù)予以保留,?
  • ????????????????以確保后面如果調(diào)用reset()重新從mark位置讀取會(huì)取得成功*/??
  • ????????int?sz?=?pos?-?markpos;??
  • ????????????????/*該實(shí)現(xiàn)是通過將緩沖區(qū)域中markpos至pos部分的移至緩沖區(qū)頭部實(shí)現(xiàn)*/??
  • ????????System.arraycopy(buffer,?markpos,?buffer,?0,?sz);??
  • ????????pos?=?sz;??
  • ????????markpos?=?0;??
  • ????????}?else?if?(buffer.length?>=?marklimit)?{??
  • ????????????????/*?如果緩沖區(qū)已經(jīng)足夠大,可以容納marklimit,則直接重置*/??
  • ????????????????markpos?=?-1;?????
  • ????????pos?=?0;/*?丟棄所有的緩沖區(qū)內(nèi)容?*/??
  • ????????}?else?{??????????
  • ????????????????/*?如果緩沖區(qū)還能增長(zhǎng)的空間,則進(jìn)行緩沖區(qū)擴(kuò)容*/??
  • ????????int?nsz?=?pos?*?2;??
  • ????????????????/*新的緩沖區(qū)大小設(shè)置成滿足最大標(biāo)記極限即可*/??
  • ????????if?(nsz?>?marklimit)??
  • ????????????nsz?=?marklimit;??
  • ????????byte?nbuf[]?=?new?byte[nsz];??
  • ????????????????//將原來的較小的緩沖內(nèi)容COPY至增容的新緩沖區(qū)中??
  • ????????System.arraycopy(buffer,?0,?nbuf,?0,?pos);??
  • ????????????????//這里使用了原子變量引用更新,確保多線程環(huán)境下內(nèi)存的可見性??
  • ????????????????if?(!bufUpdater.compareAndSet(this,?buffer,?nbuf))?{??
  • ????????????????????//?Can't?replace?buf?if?there?was?an?async?close.??
  • ????????????????????//?Note:?This?would?need?to?be?changed?if?fill()??
  • ????????????????????//?is?ever?made?accessible?to?multiple?threads.??
  • ????????????????????//?But?for?now,?the?only?way?CAS?can?fail?is?via?close.??
  • ????????????????????//?assert?buf?==?null;??
  • ????????????????????throw?new?IOException("Stream?closed");??
  • ????????????????}??
  • ????????????????buffer?=?nbuf;??
  • ????????}??
  • ????????count?=?pos;??
  • ????????//從原始輸入流中讀取數(shù)據(jù),填充緩沖區(qū)??
  • ????int?n?=?getInIfOpen().read(buffer,?pos,?buffer.length?-?pos);??
  • ????????//根據(jù)實(shí)際讀取的字節(jié)數(shù)更新緩沖區(qū)中可用字節(jié)數(shù)??
  • ????????if?(n?>?0)??
  • ????????????count?=?n?+?pos;??
  • ????}??

  • 整個(gè)fill的過程,可以看作是BufferedInputStream對(duì)外提供滑動(dòng)讀取的功能實(shí)現(xiàn),通過預(yù)先讀入一整段原始輸入流數(shù)據(jù)至緩沖區(qū)中,而外界對(duì)BufferedInputStream的讀取操作實(shí)際上是在緩沖區(qū)上進(jìn)行,如果讀取的數(shù)據(jù)超過了緩沖區(qū)的范圍,那么BufferedInputStream負(fù)責(zé)重新從原始輸入流中載入下一截?cái)?shù)據(jù)填充緩沖區(qū),然后外界繼續(xù)通過緩沖區(qū)進(jìn)行數(shù)據(jù)讀取。這樣的設(shè)計(jì)的好處是:避免了大量的磁盤IO,因?yàn)樵嫉腎nputStream類實(shí)現(xiàn)的read是即時(shí)讀取的,即每一次讀取都會(huì)是一次磁盤IO操作(哪怕只讀取了1個(gè)字節(jié)的數(shù)據(jù)),可想而知,如果數(shù)據(jù)量巨大,這樣的磁盤消耗非常可怕。而通過緩沖區(qū)的實(shí)現(xiàn),讀取可以讀取緩沖區(qū)中的內(nèi)容,當(dāng)讀取超過緩沖區(qū)的內(nèi)容后再進(jìn)行一次磁盤IO,載入一段數(shù)據(jù)填充緩沖,那么下一次讀取一般情況下就直接可以從緩沖區(qū)讀取,減少了磁盤IO。減少的磁盤IO大致可以通過以下方式計(jì)算(限r(nóng)ead()方式):?

    length? 流的最終大小?
    bufSize 緩沖區(qū)大小?

    則通過緩沖區(qū)實(shí)現(xiàn)的輸入流BufferedInputStream的磁盤IO數(shù)為原始InputStream磁盤IO的?
    1/(length/bufSize)?

    read方法解析:該方法返回當(dāng)前位置的后一位置byte值(int表示).?
    Java代碼??
  • public?synchronized?int?read()?throws?IOException?{??
  • ????if?(pos?>=?count)?{??
  • ???????????/*表示讀取位置已經(jīng)超過了緩沖區(qū)可用范圍,則對(duì)緩沖區(qū)進(jìn)行重新填充*/??
  • ????????fill();??
  • ???????????/*當(dāng)填充后再次讀取時(shí)發(fā)現(xiàn)沒有數(shù)據(jù)可讀,證明讀到了流末尾*/??
  • ????????if?(pos?>=?count)??
  • ????????return?-1;??
  • ????}??
  • ????????/*這里表示讀取位置尚未超過緩沖區(qū)有效范圍,直接返回緩沖區(qū)內(nèi)容*/??
  • ????return?getBufIfOpen()[pos++]?&?0xff;??
  • }??


  • 一次讀取多個(gè)字節(jié)(盡量讀,非貪婪)?
    Java代碼??
  • private?int?read1(byte[]?b,?int?off,?int?len)?throws?IOException?{??
  • ????int?avail?=?count?-?pos;??
  • ????if?(avail?<=?0)?{??
  • ????????/*這里使用了一個(gè)巧妙的機(jī)制,如果讀取的長(zhǎng)度大于緩沖區(qū)的長(zhǎng)度?
  • ??????????????并且沒有markpos,則直接從原始輸入流中進(jìn)行讀取,從而避免無(wú)謂的?
  • ??????????????COPY(從原始輸入流至緩沖區(qū),讀取緩沖區(qū)全部數(shù)據(jù),清空緩沖區(qū),?
  • ??????????????重新填入原始輸入流數(shù)據(jù))*/??
  • ????????if?(len?>=?getBufIfOpen().length?&&?markpos?<?0)?{??
  • ????????return?getInIfOpen().read(b,?off,?len);??
  • ????????}??
  • ????????????/*當(dāng)無(wú)數(shù)據(jù)可讀時(shí),從原始流中載入數(shù)據(jù)到緩沖區(qū)中*/??
  • ????????fill();??
  • ????????avail?=?count?-?pos;??
  • ????????if?(avail?<=?0)?return?-1;??
  • ????}??
  • ????int?cnt?=?(avail?<?len)???avail?:?len;??
  • ????????/*從緩沖區(qū)中讀取數(shù)據(jù),返回實(shí)際讀取到的大小*/??
  • ????System.arraycopy(getBufIfOpen(),?pos,?b,?off,?cnt);??
  • ????pos?+=?cnt;??
  • ????return?cnt;??
  • ????}??


  • 以下方法和上面的方法類似,唯一不同的是,上面的方法是盡量讀,讀到多少是多少,而下面的方法是貪婪的讀,沒有讀到足夠多的數(shù)據(jù)(len)就不會(huì)返回,除非讀到了流的末尾。該方法通過不斷循環(huán)地調(diào)用上面read1方法實(shí)現(xiàn)貪婪讀取。?
    Java代碼??
  • public?synchronized?int?read(byte?b[],?int?off,?int?len)??
  • ????throws?IOException??
  • ????{??
  • ????????getBufIfOpen();?//?Check?for?closed?stream??
  • ????????if?((off?|?len?|?(off?+?len)?|?(b.length?-?(off?+?len)))?<?0)?{??
  • ????????throw?new?IndexOutOfBoundsException();??
  • ????}?else?if?(len?==?0)?{??
  • ????????????return?0;??
  • ????????}??
  • ??
  • ????int?n?=?0;??
  • ????????for?(;;)?{??
  • ????????????int?nread?=?read1(b,?off?+?n,?len?-?n);??
  • ????????????if?(nread?<=?0)???
  • ????????????????return?(n?==?0)???nread?:?n;??
  • ????????????n?+=?nread;??
  • ????????????if?(n?>=?len)??
  • ????????????????return?n;??
  • ????????????//?if?not?closed?but?no?bytes?available,?return??
  • ????????????InputStream?input?=?in;??
  • ????????????if?(input?!=?null?&&?input.available()?<=?0)??
  • ????????????????return?n;??
  • ????????}??
  • ????}??

  • 略過多少字節(jié)?
    Java代碼??
  • public?synchronized?long?skip(long?n)?throws?IOException?{??
  • ????????getBufIfOpen();?//?Check?for?closed?stream??
  • ????if?(n?<=?0)?{??
  • ????????return?0;??
  • ????}??
  • ????long?avail?=?count?-?pos;??
  • ???????
  • ????????if?(avail?<=?0)?{??
  • ????????????//?If?no?mark?position?set?then?don't?keep?in?buffer??
  • ????????????//從上面的注釋可以知道,這也是一個(gè)巧妙的方法,如果沒有mark標(biāo)記,??
  • ????????????//?則直接從原始輸入流中skip??
  • ????????????if?(markpos?<0)???
  • ????????????????return?getInIfOpen().skip(n);??
  • ??????????????
  • ????????????//?Fill?in?buffer?to?save?bytes?for?reset??
  • ????????????fill();??
  • ????????????avail?=?count?-?pos;??
  • ????????????if?(avail?<=?0)??
  • ????????????????return?0;??
  • ????????}??
  • ????????//該方法的實(shí)現(xiàn)為盡量原則,不保證一定略過規(guī)定的字節(jié)數(shù)。??
  • ????????long?skipped?=?(avail?<?n)???avail?:?n;??
  • ????????pos?+=?skipped;??
  • ????????return?skipped;??
  • ????}??

  • 估計(jì)目前可用的字節(jié)數(shù),原始流中可用的字節(jié)數(shù)+緩沖區(qū)中可用的字節(jié)數(shù)?
    Java代碼??
  • public?synchronized?int?available()?throws?IOException?{??
  • ????return?getInIfOpen().available()?+?(count?-?pos);??
  • ????}??

  • 標(biāo)記位置:?
    Java代碼??
  • public?synchronized?void?mark(int?readlimit)?{??
  • ????marklimit?=?readlimit;??
  • ????markpos?=?pos;??
  • ????}??

  • 重置位置:該實(shí)現(xiàn)清晰的表明下一讀取位置被推到了以前的標(biāo)記位置,以實(shí)現(xiàn)重新讀取區(qū)段的功能?
    Java代碼??
  • public?synchronized?void?reset()?throws?IOException?{??
  • ????????getBufIfOpen();?//?Cause?exception?if?closed??
  • ????if?(markpos?<?0)??
  • ????????throw?new?IOException("Resetting?to?invalid?mark");??
  • ????pos?=?markpos;??
  • ????}??


  • 關(guān)閉流:首先通過線程安全的方式設(shè)置了內(nèi)部的緩沖區(qū)引用為空,然后再對(duì)原始輸入流進(jìn)行關(guān)閉。?
    Java代碼??
  • public?void?close()?throws?IOException?{??
  • ????????byte[]?buffer;??
  • ????????while?(?(buffer?=?buf)?!=?null)?{??
  • ????????????if?(bufUpdater.compareAndSet(this,?buffer,?null))?{??
  • ????????????????InputStream?input?=?in;??
  • ????????????????in?=?null;??
  • ????????????????if?(input?!=?null)??
  • ????????????????????input.close();??
  • ????????????????return;??
  • ????????????}??
  • ????????????//?Else?retry?in?case?a?new?buf?was?CASed?in?fill()??
  • ????????}??
  • ????} ?
  • 總結(jié)

    以上是生活随笔為你收集整理的BufferedInputStream学习笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。