生活随笔
收集整理的這篇文章主要介紹了
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??? ?? protected?volatile?byte?buf[];??? ?? private?static?final?AtomicReferenceFieldUpdater<BufferedInputStream,?byte[]>?bufUpdater?=?AtomicReferenceFieldUpdater.newUpdater(BufferedInputStream.class,??byte[].class,?"buf")?? ?? protected?int?count;?? ?? protected?int?pos;?? ?? protected?int?markpos?=?-1;?? ?? protected?int?marklimit;?? 通過構(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)?{?? ??????????? ? ? ?? ????????pos?=?0;?????????? ????}else?if?(pos?>=?buffer.length){?? ????????? ????????if?(markpos?>?0)?{????? ?????????????? ?? ????????int?sz?=?pos?-?markpos;?? ?????????????????? ????????System.arraycopy(buffer,?markpos,?buffer,?0,?sz);?? ????????pos?=?sz;?? ????????markpos?=?0;?? ????????}?else?if?(buffer.length?>=?marklimit)?{?? ?????????????????? ????????????????markpos?=?-1;????? ????????pos?=?0;?? ????????}?else?{?????????? ?????????????????? ????????int?nsz?=?pos?*?2;?? ?????????????????? ????????if?(nsz?>?marklimit)?? ????????????nsz?=?marklimit;?? ????????byte?nbuf[]?=?new?byte[nsz];?? ?????????????????? ????????System.arraycopy(buffer,?0,?nbuf,?0,?pos);?? ?????????????????? ????????????????if?(!bufUpdater.compareAndSet(this,?buffer,?nbuf))?{?? ?????????????????????? ?????????????????????? ?????????????????????? ?????????????????????? ?????????????????????? ????????????????????throw?new?IOException("Stream?closed");?? ????????????????}?? ????????????????buffer?=?nbuf;?? ????????}?? ????????count?=?pos;?? ?????????? ????int?n?=?getInIfOpen().read(buffer,?pos,?buffer.length?-?pos);?? ?????????? ????????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)?{?? ????????????? ????????fill();?? ????????????? ????????if?(pos?>=?count)?? ????????return?-1;?? ????}?? ?????????? ????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)?{?? ????????? ? ? ?? ????????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;?? ????}?? 以下方法和上面的方法類似,唯一不同的是,上面的方法是盡量讀,讀到多少是多少,而下面的方法是貪婪的讀,沒有讀到足夠多的數(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();??? ????????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;?? ?????????????? ????????????InputStream?input?=?in;?? ????????????if?(input?!=?null?&&?input.available()?<=?0)?? ????????????????return?n;?? ????????}?? ????}?? 略過多少字節(jié)? Java代碼??
public?synchronized?long?skip(long?n)?throws?IOException?{?? ????????getBufIfOpen();??? ????if?(n?<=?0)?{?? ????????return?0;?? ????}?? ????long?avail?=?count?-?pos;?? ??????? ????????if?(avail?<=?0)?{?? ?????????????? ?????????????? ?????????????? ????????????if?(markpos?<0)??? ????????????????return?getInIfOpen().skip(n);?? ?????????????? ?????????????? ????????????fill();?? ????????????avail?=?count?-?pos;?? ????????????if?(avail?<=?0)?? ????????????????return?0;?? ????????}?? ?????????? ????????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();??? ????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;?? ????????????}?? ?????????????? ????????}?? ????} ?
總結(jié)
以上是生活随笔為你收集整理的BufferedInputStream学习笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。