Java IO学习之缓冲输入流(BufferedInputStream)
JavaIO BufferedInputStream
概要:
BufferedInputStream是缓冲输入流,继承于FilterInputStream,作用是为另一个输入流添加一些功能,本质上是通过一个内部缓冲数组实现的。例如,在新建某输入流对应的BufferedInputStream后,当通过read()读取数据时,BufferedInputStream会将输入流的数据分批的填入到缓冲区中,每当缓冲区的数据读完之后,输入流会再次填充数据缓冲区,直到读完数据。
BufferedInputStream主要的函数列表:
BufferedInputStream(InputStreamin) BufferedInputStream(InputStreamin,intsize) synchronizedintavailable() voidclose() synchronizedvoidmark(intreadlimit) booleanmarkSupported() synchronizedintread() synchronizedintread(byte[]buffer,intoffset,intbyteCount) synchronizedvoidreset() synchronizedlongskip(longbyteCount)
示例代码:
publicclassBufferedInputStreamTest{ privatestaticfinalintLEN=5; publicstaticvoidmain(String[]args){ testBufferedInputStream(); } privatestaticvoidtestBufferedInputStream(){ //创建BufferedInputStream字节流,内容是ArrayLetters数组 try{ Filefile=newFile("file.txt"); InputStreamin=newBufferedInputStream(newFileInputStream(file),512); //从字节流中读取5个字节。“abcde”,a对应0x61,b对应0x62,依次类推... for(inti=0;i<LEN;i++){ //若能继续读取下一个字节,则读取下一个字节 if(in.available()>=0){ //读取“字节流的下一个字节” inttmp=in.read(); System.out.printf("%d:0x%s\n",i,Integer.toHexString(tmp)); } } //若“该字节流”不支持标记功能,则直接退出 if(!in.markSupported()){ System.out.println("makenotsupported!"); return; } //标记“当前索引位置”,即标记第6个位置的元素--“f” //1024对应marklimit in.mark(1024); //跳过22个字节。 in.skip(22); //读取5个字节 byte[]buf=newbyte[LEN]; in.read(buf,0,LEN); //将buf转换为String字符串。 Stringstr1=newString(buf); System.out.printf("str1=%s\n",str1); //重置“输入流的索引”为mark()所标记的位置,即重置到“f”处。 in.reset(); //从“重置后的字节流”中读取5个字节到buf中。即读取“fghij” in.read(buf,0,LEN); //将buf转换为String字符串。 Stringstr2=newString(buf); System.out.printf("str2=%s\n",str2); in.close(); }catch(FileNotFoundExceptione){ e.printStackTrace(); }catch(SecurityExceptione){ e.printStackTrace(); }catch(IOExceptione){ e.printStackTrace(); } } }
运行结果:
0:0x61 1:0x62 2:0x63 3:0x64 4:0x65 str1=12345 str2=fghij
基于JDK8的BufferInputStream代码:
publicclassBufferedInputStreamextendsFilterInputStream{ privatestaticintDEFAULT_BUFFER_SIZE=8192;//默认缓冲区大小为8X1024 privatestaticintMAX_BUFFER_SIZE=Integer.MAX_VALUE-8; protectedvolatilebytebuf[];//缓冲数组 /** *AtomicupdatertoprovidecompareAndSetforbuf.Thisis *necessarybecauseclosescanbeasynchronous.Weusenullness *ofbuf[]asprimaryindicatorthatthisstreamisclosed.(The *"in"fieldisalsonulledoutonclose.) */ privatestaticfinalAtomicReferenceFieldUpdater<BufferedInputStream,byte[]>bufUpdater= AtomicReferenceFieldUpdater.newUpdater(BufferedInputStream.class,byte[].class,"buf"); //值在0到buf.len之间 protectedintcount; //在buffer的当前位置,下一个字符被读取 protectedintpos; //值为mark函数最近被调用的时候,值为-1到pos protectedintmarkpos=-1; /** *Themaximumreadaheadallowedafteracalltothe *<code>mark</code>methodbeforesubsequentcallstothe *<code>reset</code>methodfail. *Wheneverthedifferencebetween<code>pos</code> *and<code>markpos</code>exceeds<code>marklimit</code>, *thenthemarkmaybedroppedbysetting *<code>markpos</code>to<code>-1</code>. * *@seejava.io.BufferedInputStream#mark(int) *@seejava.io.BufferedInputStream#reset() */ protectedintmarklimit; /** *Checktomakesurethatunderlyinginputstreamhasnotbeen *nulledoutduetoclose;ifnotreturnit; */ // privateInputStreamgetInIfOpen()throwsIOException{ InputStreaminput=in; if(input==null) thrownewIOException("Streamclosed"); returninput; } /** *Checktomakesurethatbufferhasnotbeennulledoutdueto *close;ifnotreturnit; */ privatebyte[]getBufIfOpen()throwsIOException{ byte[]buffer=buf; if(buffer==null) thrownewIOException("Streamclosed"); returnbuffer; } /** *Createsa<code>BufferedInputStream</code> *andsavesitsargument,theinputstream *<code>in</code>,forlateruse.Aninternal *bufferarrayiscreatedandstoredin<code>buf</code>. * *@paramintheunderlyinginputstream. */ //带InputStream的构造函数 publicBufferedInputStream(InputStreamin){ this(in,DEFAULT_BUFFER_SIZE); } /** *Createsa<code>BufferedInputStream</code> *withthespecifiedbuffersize, *andsavesitsargument,theinputstream *<code>in</code>,forlateruse.Aninternal *bufferarrayoflength<code>size</code> *iscreatedandstoredin<code>buf</code>. * *@paramintheunderlyinginputstream. *@paramsizethebuffersize. *@exceptionIllegalArgumentExceptionif{@codesize<=0}. */ //带InputStream和大小的构造函数 publicBufferedInputStream(InputStreamin,intsize){ super(in); if(size<=0){ thrownewIllegalArgumentException("Buffersize<=0"); } buf=newbyte[size]; } /** *Fillsthebufferwithmoredata,takingintoaccount *shufflingandothertricksfordealingwithmarks. *Assumesthatitisbeingcalledbyasynchronizedmethod. *Thismethodalsoassumesthatalldatahasalreadybeenreadin, *hencepos>count. */ // privatevoidfill()throwsIOException{ byte[]buffer=getBufIfOpen(); if(markpos<0) pos=0;/*nomark:throwawaythebuffer*/ elseif(pos>=buffer.length)/*noroomleftinbuffer*/ if(markpos>0){/*canthrowawayearlypartofthebuffer*/ intsz=pos-markpos; System.arraycopy(buffer,markpos,buffer,0,sz); pos=sz; markpos=0; }elseif(buffer.length>=marklimit){ markpos=-1;/*buffergottoobig,invalidatemark*/ pos=0;/*dropbuffercontents*/ }elseif(buffer.length>=MAX_BUFFER_SIZE){ thrownewOutOfMemoryError("Requiredarraysizetoolarge"); }else{/*growbuffer*/ intnsz=(pos<=MAX_BUFFER_SIZE-pos)? pos*2:MAX_BUFFER_SIZE; if(nsz>marklimit) nsz=marklimit; bytenbuf[]=newbyte[nsz]; System.arraycopy(buffer,0,nbuf,0,pos); if(!bufUpdater.compareAndSet(this,buffer,nbuf)){ //Can'treplacebufiftherewasanasyncclose. //Note:Thiswouldneedtobechangediffill() //isevermadeaccessibletomultiplethreads. //Butfornow,theonlywayCAScanfailisviaclose. //assertbuf==null; thrownewIOException("Streamclosed"); } buffer=nbuf; } count=pos; intn=getInIfOpen().read(buffer,pos,buffer.length-pos); if(n>0) count=n+pos; } /** *See *thegeneralcontractofthe<code>read</code> *methodof<code>InputStream</code>. * *@returnthenextbyteofdata,or<code>-1</code>iftheendofthe *streamisreached. *@exceptionIOExceptionifthisinputstreamhasbeenclosedby *invokingits{@link#close()}method, *oranI/Oerroroccurs. *@seejava.io.FilterInputStream#in */ //读下一个字节,没有数据返回-1 publicsynchronizedintread()throwsIOException{ if(pos>=count){ fill(); if(pos>=count) return-1; } returngetBufIfOpen()[pos++]&0xff; } /** *Readcharactersintoaportionofanarray,readingfromtheunderlying *streamatmostonceifnecessary. */ privateintread1(byte[]b,intoff,intlen)throwsIOException{ intavail=count-pos; if(avail<=0){ /*Iftherequestedlengthisatleastaslargeasthebuffer,and ifthereisnomark/resetactivity,donotbothertocopythe bytesintothelocalbuffer.Inthiswaybufferedstreamswill cascadeharmlessly.*/ if(len>=getBufIfOpen().length&&markpos<0){ returngetInIfOpen().read(b,off,len); } fill(); avail=count-pos; if(avail<=0)return-1; } intcnt=(avail<len)?avail:len; System.arraycopy(getBufIfOpen(),pos,b,off,cnt); pos+=cnt; returncnt; } /** *Readsbytesfromthisbyte-inputstreamintothespecifiedbytearray, *startingatthegivenoffset. * *<p>Thismethodimplementsthegeneralcontractofthecorresponding *<code>{@linkInputStream#read(byte[],int,int)read}</code>methodof *the<code>{@linkInputStream}</code>class.Asanadditional *convenience,itattemptstoreadasmanybytesaspossiblebyrepeatedly *invokingthe<code>read</code>methodoftheunderlyingstream.This *iterated<code>read</code>continuesuntiloneofthefollowing *conditionsbecomestrue:<ul> * *<li>Thespecifiednumberofbyteshavebeenread, * *<li>The<code>read</code>methodoftheunderlyingstreamreturns *<code>-1</code>,indicatingend-of-file,or * *<li>The<code>available</code>methodoftheunderlyingstream *returnszero,indicatingthatfurtherinputrequestswouldblock. * *</ul>Ifthefirst<code>read</code>ontheunderlyingstreamreturns *<code>-1</code>toindicateend-of-filethenthismethodreturns *<code>-1</code>.Otherwisethismethodreturnsthenumberofbytes *actuallyread. * *<p>Subclassesofthisclassareencouraged,butnotrequired,to *attempttoreadasmanybytesaspossibleinthesamefashion. * *@parambdestinationbuffer. *@paramoffoffsetatwhichtostartstoringbytes. *@paramlenmaximumnumberofbytestoread. *@returnthenumberofbytesread,or<code>-1</code>iftheendof *thestreamhasbeenreached. *@exceptionIOExceptionifthisinputstreamhasbeenclosedby *invokingits{@link#close()}method, *oranI/Oerroroccurs. */ // publicsynchronizedintread(byteb[],intoff,intlen)throwsIOException { getBufIfOpen();//Checkforclosedstream if((off|len|(off+len)|(b.length-(off+len)))<0){ thrownewIndexOutOfBoundsException(); }elseif(len==0){ return0; } intn=0; for(;;){ intnread=read1(b,off+n,len-n); if(nread<=0) return(n==0)?nread:n; n+=nread; if(n>=len) returnn; //ifnotclosedbutnobytesavailable,return InputStreaminput=in; if(input!=null&&input.available()<=0) returnn; } } /** *Seethegeneralcontractofthe<code>skip</code> *methodof<code>InputStream</code>. * *@exceptionIOExceptionifthestreamdoesnotsupportseek, *orifthisinputstreamhasbeenclosedby *invokingits{@link#close()}method,oran *I/Oerroroccurs. */ //跳过n长的数据 publicsynchronizedlongskip(longn)throwsIOException{ getBufIfOpen();//Checkforclosedstream if(n<=0){ return0; } longavail=count-pos; if(avail<=0){ //Ifnomarkpositionsetthendon'tkeepinbuffer if(markpos<0) returngetInIfOpen().skip(n); //Fillinbuffertosavebytesforreset fill(); avail=count-pos; if(avail<=0) return0; } longskipped=(avail<n)?avail:n; pos+=skipped; returnskipped; } /** *Returnsanestimateofthenumberofbytesthatcanberead(or *skippedover)fromthisinputstreamwithoutblockingbythenext *invocationofamethodforthisinputstream.Thenextinvocationmightbe *thesamethreadoranotherthread.Asinglereadorskipofthis *manybyteswillnotblock,butmayreadorskipfewerbytes. *<p> *Thismethodreturnsthesumofthenumberofbytesremainingtobereadin *thebuffer(<code>count-pos</code>)andtheresultofcallingthe *{@linkjava.io.FilterInputStream#inin}.available(). * *@returnanestimateofthenumberofbytesthatcanberead(orskipped *over)fromthisinputstreamwithoutblocking. *@exceptionIOExceptionifthisinputstreamhasbeenclosedby *invokingits{@link#close()}method, *oranI/Oerroroccurs. */ //返回还有多少数据可以读 publicsynchronizedintavailable()throwsIOException{ intn=count-pos; intavail=getInIfOpen().available(); returnn>(Integer.MAX_VALUE-avail)?Integer.MAX_VALUE:n+avail; } /** *Seethegeneralcontractofthe<code>mark</code> *methodof<code>InputStream</code>. * *@paramreadlimitthemaximumlimitofbytesthatcanbereadbefore *themarkpositionbecomesinvalid. *@seejava.io.BufferedInputStream#reset() */ publicsynchronizedvoidmark(intreadlimit){ marklimit=readlimit; markpos=pos; } /** *Seethegeneralcontractofthe<code>reset</code> *methodof<code>InputStream</code>. *<p> *If<code>markpos</code>is<code>-1</code> *(nomarkhasbeensetorthemarkhasbeen *invalidated),an<code>IOException</code> *isthrown.Otherwise,<code>pos</code>is *setequalto<code>markpos</code>. * *@exceptionIOExceptionifthisstreamhasnotbeenmarkedor, *ifthemarkhasbeeninvalidated,orthestream *hasbeenclosedbyinvokingits{@link#close()} *method,oranI/Oerroroccurs. *@seejava.io.BufferedInputStream#mark(int) */ publicsynchronizedvoidreset()throwsIOException{ getBufIfOpen();//Causeexceptionifclosed if(markpos<0) thrownewIOException("Resettingtoinvalidmark"); pos=markpos; } /** *Testsifthisinputstreamsupportsthe<code>mark</code> *and<code>reset</code>methods.The<code>markSupported</code> *methodof<code>BufferedInputStream</code>returns *<code>true</code>. * *@returna<code>boolean</code>indicatingifthisstreamtypesupports *the<code>mark</code>and<code>reset</code>methods. *@seejava.io.InputStream#mark(int) *@seejava.io.InputStream#reset() */ //是否支持标记 publicbooleanmarkSupported(){ returntrue; } /** *Closesthisinputstreamandreleasesanysystemresources *associatedwiththestream. *Oncethestreamhasbeenclosed,furtherread(),available(),reset(), *orskip()invocationswillthrowanIOException. *Closingapreviouslyclosedstreamhasnoeffect. * *@exceptionIOExceptionifanI/Oerroroccurs. */ //关闭资源 publicvoidclose()throwsIOException{ byte[]buffer; while((buffer=buf)!=null){ if(bufUpdater.compareAndSet(this,buffer,null)){ InputStreaminput=in; in=null; if(input!=null) input.close(); return; } //ElseretryincaseanewbufwasCASedinfill() } } }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!