day19(中)_IO流3(模拟缓冲区,装饰设计模式)
生活随笔
收集整理的這篇文章主要介紹了
day19(中)_IO流3(模拟缓冲区,装饰设计模式)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?
1.MyBufferedReader和MyBufferedInputStream
1.模擬字符讀取流的緩沖區:
/*根據readLine原理:自定義一個類包含一個功能和readLine一致的方法來模擬以下BufferedReader方法 */ package myreadline; import java.io.FileReader; import java.io.IOException;class MyBufferedReader{private FileReader r;//需要用到FileReader的read方法,因此初始化時傳入FileReader對象private char[] chArr=new char[1024];private int pointer=0;MyBufferedReader(FileReader r){this.r=r;}//自定義readLine方法public String readLine()throws IOException{//自定義功能不在內部處理,而是拋出去,讓調用者處理 StringBuilder sb=new StringBuilder();//定義一個臨時容器模擬緩沖區int ch=0;while((ch=r.read())!=-1){if(ch=='\r') continue;//讀下一個進行判斷elseif(ch=='\n')return sb.toString();elsesb.append((char)ch);} /* ①以上代碼也不可寫成 if(ch==’\r’||ch==’\n’) returnsb.toString() 因為當讀到'\r’ 立即返回改行數據, 但是下次會讀'\n’ 會再次返回,此時StringBuilder無數據 ②如果當前平臺的換行為'\r’以上方法并不適用 以上方法僅適用與\r\n或\n換行 此時直接 if(ch==’\r’) return sb.toString(); else return sb.append((char)ch); ③對于以上代碼可能發生一種情況:當讀到文件最后一行:例如:abcd后面沒有回車,此時執行不到sb.toString(),也就是說:雖然存入容器但是這一行不能返回. 那么加上一個判斷(如下): */if(sb.length()!=0)return sb.toString(); return null;//此時讀到文件末尾 }//模擬自定義緩沖區,把關閉單獨封裝在一個方法中public void myClose()throws IOException{r.close();}public static void main(String[] args){MyBufferedReader mbr=null;try{mbr=new MyBufferedReader(new FileReader("4_MyBufferedReader.java"));String line=null;while((line=mbr.readLine_2())!=null)System.out.println(line);}catch(IOException e){throw new RuntimeException("讀異常");}finally{try{if(mbr!=null)mbr.myClose();}catch(IOException e){throw new RuntimeException("關閉異常");}}} }?
/* 如果不利用StringBuilder而利用 字符數組 */ public String readLine_2()throws IOException{pointer=0;int ch=0;while((ch=r.read())!=-1){if(ch=='\r')continue;elseif(ch=='\n')return new String(chArr,0,pointer);elsechArr[pointer++]=(char)ch; }if(pointer!=0)return new String(chArr,0,pointer);return null; }2.模擬字節讀取流緩沖區:
/* 自定義緩沖區:算法思想:參照示意圖 */ package mybuffered; import java.io.InputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io. BufferedOutputStream; class MyBufferedInputStream{private byte[] buff=new byte[1024];private InputStream is=null;private int pointer=0;//指針用于取出緩沖區(數組)中的元素private int count=0;//計數器用于記錄每次從文件中取出的字節數 MyBufferedInputStream(InputStream is){this.is=is;}public int myBufferedRead()throws IOException{if(count==0){//只有當緩沖區中的數據被讀完時,再從文件中//取一部分數據count=is.read(buff);pointer=0;//當count==0,把指針重新移到0角標 }if(count!=-1){//是否到達文件尾--count;//讀取一個字節,count-1return (int)buff[pointer++] & 255;//0x00ff }elsereturn -1;}public void close()throws IOException{is.close();} }class TestBuffered{public static void main(String[] args)throws IOException{ //用自定義緩沖區拷貝MP3 MyBufferedInputStream mbis=new MyBufferedInputStream(new FileInputStream("e:\\song\\Amy Diamond - Heartbeats.mp3"));BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("c:\\Hertbeats.mp3"));long start=System.currentTimeMillis();int aByte=0;System.out.println(aByte=(mbis.myBufferedRead())); while((aByte=(mbis.myBufferedRead()))!=-1){//從自定義緩沖區中讀一個字節,寫入到系統的緩沖區 bos.write(aByte);bos.flush();}long end=System.currentTimeMillis();System.out.println(end-start+"ms");//時間的長短和cpu性能以及其它因素有關 bos.close();mbis.close();} }2.裝飾設計模式:
①概述:
/* 裝飾設計模式:(目前學的第三種設計模式) 當想要對已有的對象進行功能增強時可以定義類,將已有對象(new FileReader)傳入,基于已有的功能(read),并提供加強功能(myReadLine).那么自定義的該類成為裝飾類.裝飾類通常會通過構造方法接收被裝飾的對象 并基于被裝飾的對象的功能,提供更強的功能*/ //例如:增強人的吃飯功能 class Person{public void eat(){System.out.println("吃飯");} } class SuperPerson{private Person p;SuperPerson(Person p){this.p=p;}public void superEat(){System.out.println("喝小酒");p.eat();System.out.println("甜點");System.out.println("整一根");} } class PersonDemo{public static void main(String[] args){Person p=new Person(); p.eat();new SuperPerson(p).superEat();} } /*到目前為止已經學到3中設計模式:1.單例設計模式2.模板方法設計模式3.裝飾設計模式 */②※裝飾相對繼承優點:
/*在人吃飯例子中,可以不用裝飾類,我直接讓SuperPerson extends Person,然后復寫eat方法不也OK?在舉例說明為什么要有裝飾設計模式?//MyTextReader類用來操作文件讀取,為了提高讀操作效率,使用緩沖區技術//又定義一個類MyBufferedTextReader繼承它,提供更高效的readLine方法MyReader <--MyTextReader<--MyBufferedTextReader<--MyMediaReader<--MyBufferedMediaReader//讀取多媒體文件,然后為了提高讀效率,使用緩沖區<--MyDataReader<--MyBufferedDataReader//同理...... 那么,我后期在來個類用于操作讀取其它文件,為了高效還得定義緩沖區子類,產生一些缺點:1.使整個體系變得異常冗雜2.后期的擴展性極差那么干脆:找到其參數的共同類型.通過多態形式.可以提高擴展性MyBufferedReader extends MyReader{private MyReader mr;pubic MyBufferedReader(MyReader mr){//MyReader的子類對象均能傳入this.mr=mr; //誰需要使用緩沖技術,把它傳進來}}簡化了原有體系結構:MyReader<--MyTextReader<--MyMediaReader<--MyDataReader <--MyBufferedReader*//* 裝飾設計模式對比繼承:1.裝飾設計模式比繼承更加靈活提高擴展性,避免了繼承的冗雜而且降低了類與類之間關系2.裝飾類因為增強已有對象,具備的功能和已有的功能是相同的只不過提供了更強的功能(這個功能是原有的增強,而不是從本質上改變原有功能:在Reader體系中,例如:裝飾類BufferedReader,其中readLine就是增強了FileReader中read功能)那么裝飾類和被裝飾類通常是同屬于一個體系(具有共同的父類/父接口) */?
鑒于以上我們可以把自定義緩沖區的代碼優化下: (改進自定義字符讀取流緩沖區)
//把MyBufferedReader修改為裝飾類: package myreadline; import java.io.FileReader; import java.io.IOException; import java.io.Reader; public class MyBufferedReader2 extends Reader{//繼承Reader,那么必須復寫Reader中抽象方法,不然無法創建對象 private Reader r; public MyBufferedReader2(Reader r){//多態提高擴展性this.r=r; }public String readLine()throws IOException{StringBuilder sb=new StringBuilder();int ch=0;while((ch=r.read())!=-1){if(ch=='\r') continue;//讀下一個進行判斷elseif(ch=='\n')return sb.toString();elsesb.append((char)ch);} if(sb.length()!=0)return sb.toString(); return null; }//復寫close方法public void close()throws IOException{r.close();}//復寫abstract int read(char[] cbuf, int off, int len)public int read(char[] cbuf, int off, int len)throws IOException{return r .read(cbuf,off,len);//利用了 傳入對象已復寫該方法 }public static void main(String[] args){MyBufferedReader mbr=null;try{mbr=new MyBufferedReader(new FileReader("4_MyBufferedReader.java"));String line=null;while((line=mbr.readLine())!=null)System.out.println(line);}catch(IOException e){throw new RuntimeException("讀異常");}finally{try{if(mbr!=null)mbr.close();}catch(IOException e){throw new RuntimeException("關閉異常");}}} }3.BufferedReader子類LineNumberReader(相對于BufferedReader提供更強功能)
①.LineNumberReader示例:
/* 在BufferedReader下有一個子類:LineNumberReader跟蹤行號的緩沖字符輸入流,進一步加強功能.打印每行的同時可以帶上行號 */ package bufferedreader; import java.io.LineNumberReader; import java.io.FileReader; import java.io.IOException; class LineNumberReaderDemo{public static void main(String[] args){LineNumberReader lnr=null;try{lnr=new LineNumberReader(new FileReader("7_LineNumberReader.java"));String line=null;lnr.setLineNumber(10);//那么行號將從11開始while((line=lnr.readLine())!=null)System.out.println(lnr.getLineNumber()+":"+line);}catch(IOException e){e.printStackTrace();}finally{try{if(lnr!=null)lnr.close();}catch(IOException e){e.printStackTrace();}}} }②自定義MyLineNumberReader方法:
package mylinenumber;import java.io.Reader; import java.io.FileReader; import java.io.IOException; import myreadline.MyBufferedReader2;class MyLineNumberReader extends MyBufferedReader2{//在MyBufferedReader2已有方法,不再重復定義private int lineNumber=0;//行號public MyLineNumberReader(Reader r){super(r);}//設置行號public void mySetLineNumber(int lineNumber){this.lineNumber=lineNumber;}//獲取行號public int myGetLineNumber(){return lineNumber; }public String myReadLine()throws IOException{++lineNumber;//讀一行自增一次return super.readLine();//提高代碼重用性 }}class MyLineNumberDemo{public static void main(String[] args){MyLineNumberReader mlnr=null;try{mlnr=new MyLineNumberReader(new FileReader("8_MyLineNumberReader.java"));String line=null;mlnr.mySetLineNumber(100);while((line=mlnr.myReadLine())!=null)System.out.println(mlnr.myGetLineNumber()+":"+line);}catch(IOException e){e.printStackTrace();}finally{try{if(mlnr!=null)mlnr.close();}catch(IOException e){e.printStackTrace();}}} }轉載于:https://www.cnblogs.com/yiqiu2324/archive/2013/05/18/3085750.html
總結
以上是生活随笔為你收集整理的day19(中)_IO流3(模拟缓冲区,装饰设计模式)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Response. AppendHead
- 下一篇: c++标准库中,含有链表的类list