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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BufferedInputStream学习笔记

發布時間:2023/12/10 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BufferedInputStream学习笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【本文轉載于http://icanfly.iteye.com/blog/1207397】


BufferedInputStream是一個帶有緩沖區域的InputStream,它的繼承體系如下:?

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

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

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

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



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



  • 這個類中最為重要的方法是fill()方法,它提供了緩沖區域的讀取、寫入、區域元素的移動更新等。下面著重分析一下該方法:?
    Java代碼??
  • private?void?fill()?throws?IOException?{??
  • ????????byte[]?buffer?=?getBufIfOpen();??
  • ????if?(markpos?<?0)?{??
  • ??????????/*如果不存在標記位置(即沒有需要進行reset的位置需求)?
  • ????????????則可以進行大膽地直接重置pos標識下一可讀取位置,但是這樣?
  • ????????????不是會讀取到以前的舊數據嗎?不用擔心,在后面的代碼里會實現輸入流的新??
  • ????????????數據填充*/??
  • ????????pos?=?0;??????????
  • ????}else?if?(pos?>=?buffer.length){??
  • ???????/*?位置大于緩沖區長度,這里表示已經沒有可用空間了?*/??
  • ????????if?(markpos?>?0)?{?????
  • ?????????????/*?表示存在mark位置,則要對mark位置到pos位置的數據予以保留,?
  • ????????????????以確保后面如果調用reset()重新從mark位置讀取會取得成功*/??
  • ????????int?sz?=?pos?-?markpos;??
  • ????????????????/*該實現是通過將緩沖區域中markpos至pos部分的移至緩沖區頭部實現*/??
  • ????????System.arraycopy(buffer,?markpos,?buffer,?0,?sz);??
  • ????????pos?=?sz;??
  • ????????markpos?=?0;??
  • ????????}?else?if?(buffer.length?>=?marklimit)?{??
  • ????????????????/*?如果緩沖區已經足夠大,可以容納marklimit,則直接重置*/??
  • ????????????????markpos?=?-1;?????
  • ????????pos?=?0;/*?丟棄所有的緩沖區內容?*/??
  • ????????}?else?{??????????
  • ????????????????/*?如果緩沖區還能增長的空間,則進行緩沖區擴容*/??
  • ????????int?nsz?=?pos?*?2;??
  • ????????????????/*新的緩沖區大小設置成滿足最大標記極限即可*/??
  • ????????if?(nsz?>?marklimit)??
  • ????????????nsz?=?marklimit;??
  • ????????byte?nbuf[]?=?new?byte[nsz];??
  • ????????????????//將原來的較小的緩沖內容COPY至增容的新緩沖區中??
  • ????????System.arraycopy(buffer,?0,?nbuf,?0,?pos);??
  • ????????????????//這里使用了原子變量引用更新,確保多線程環境下內存的可見性??
  • ????????????????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;??
  • ????????//從原始輸入流中讀取數據,填充緩沖區??
  • ????int?n?=?getInIfOpen().read(buffer,?pos,?buffer.length?-?pos);??
  • ????????//根據實際讀取的字節數更新緩沖區中可用字節數??
  • ????????if?(n?>?0)??
  • ????????????count?=?n?+?pos;??
  • ????}??

  • 整個fill的過程,可以看作是BufferedInputStream對外提供滑動讀取的功能實現,通過預先讀入一整段原始輸入流數據至緩沖區中,而外界對BufferedInputStream的讀取操作實際上是在緩沖區上進行,如果讀取的數據超過了緩沖區的范圍,那么BufferedInputStream負責重新從原始輸入流中載入下一截數據填充緩沖區,然后外界繼續通過緩沖區進行數據讀取。這樣的設計的好處是:避免了大量的磁盤IO,因為原始的InputStream類實現的read是即時讀取的,即每一次讀取都會是一次磁盤IO操作(哪怕只讀取了1個字節的數據),可想而知,如果數據量巨大,這樣的磁盤消耗非常可怕。而通過緩沖區的實現,讀取可以讀取緩沖區中的內容,當讀取超過緩沖區的內容后再進行一次磁盤IO,載入一段數據填充緩沖,那么下一次讀取一般情況下就直接可以從緩沖區讀取,減少了磁盤IO。減少的磁盤IO大致可以通過以下方式計算(限read()方式):?

    length? 流的最終大小?
    bufSize 緩沖區大小?

    則通過緩沖區實現的輸入流BufferedInputStream的磁盤IO數為原始InputStream磁盤IO的?
    1/(length/bufSize)?

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


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


  • 以下方法和上面的方法類似,唯一不同的是,上面的方法是盡量讀,讀到多少是多少,而下面的方法是貪婪的讀,沒有讀到足夠多的數據(len)就不會返回,除非讀到了流的末尾。該方法通過不斷循環地調用上面read1方法實現貪婪讀取。?
    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;??
  • ????????}??
  • ????}??

  • 略過多少字節?
    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??
  • ????????????//從上面的注釋可以知道,這也是一個巧妙的方法,如果沒有mark標記,??
  • ????????????//?則直接從原始輸入流中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;??
  • ????????}??
  • ????????//該方法的實現為盡量原則,不保證一定略過規定的字節數。??
  • ????????long?skipped?=?(avail?<?n)???avail?:?n;??
  • ????????pos?+=?skipped;??
  • ????????return?skipped;??
  • ????}??

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

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

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


  • 關閉流:首先通過線程安全的方式設置了內部的緩沖區引用為空,然后再對原始輸入流進行關閉。?
    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()??
  • ????????}??
  • ????} ?
  • 總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。