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()
}
}
}
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!