將文本寫入字符輸出流,緩衝各個字符,從而提供單個字符、數組和字符串的高效寫入。 java
緩衝區的出現是爲了提升流的操做效率而出現的。因此在建立緩衝區以前,必需要先有流對象。設計模式
void newLine():寫入一個行分隔符。(跨平臺換行符)
數組
import java.io.*; class BufferedWriterDemo { pubilc static void main(String[] args)Throws IOException { //建立一個字符寫入流對象。 FileWriter fw = new FileWriter("buf.txt"); //爲了提升字符流寫入效率,加入了緩衝技術。原理:對象裏面封裝了數組。只要將須要被提升效率的流對象做爲參數傳遞給緩衝區的構造函數便可。 BufferedWriter bufw = new BufferedWriter(fw); buyw.write("abcde"); //記住,只要用到緩衝區,就要記得刷新。 bufw.flush(); //其實關閉緩衝區,就是在關閉緩衝區的流對象。 bufw.close(); } }
從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取。app
String readLine():讀取一個文本行。(該緩衝區提供了一個一次讀一行的方法,方便與對文本數據的獲取。當返回null時,表示讀到文件末尾。
函數
import java.io.*; class BufferReaderDemo { pubic static void main(String[] args) { //建立一個讀取流對象與文件相關聯。 FileReader fr = new FileReader("buf.txt"); //爲了提升效率,加入緩衝技術,將字符讀取流對象做爲參數傳遞給緩衝對象的構造函數。 BufferedReader bufr = new BufferedReader(fr); String line = null; while((line=bufr.readLIne()) !null) { System.out.pritnln(line); } bufr.close(); } }
練習:經過緩衝區複製一個.java文件。優化
readLine方法返回的時候只返回回車符以前的數據內容。並不返回回車符。ui
readLine方法原理:不管是讀一行,獲取讀取多個字符,其實最終都是在硬盤上一個一個讀取,因此最終使用的仍是read方法,一次讀一個的方法。this
import java.io.*; class CopyTestByBuf { public static void main(String[] args) { BufferReader bufr = null; BufferWriter bufw = null; try { bufr = new BufferReader(new FileReader("BufferedWriterDemo.java")); bufw = new BufferedWriter(new FileWriter("bufWriter_copy.txt")); String line = null; while((line = bufr.readLine())!=null) { bufw.write(line); bufw.newLine(); bufw.fiush(); } ctach(IOException e) { throw new RuntimeException("讀寫失敗"); } finally { try { if(bufr!=null) bufr.close(); } catch(IOException e) { throw new RuntimeException("讀取關閉失敗"); } try { if(bufw!=null) bufw.close(); } catch(IOException e) { throw new RuntimeException("寫入關閉失敗"); } } } } }
明白了BufferedReader類中特有方法readLine的原理後,能夠自定義一個類中包含一個功能和readLine一致的方法。來模擬一下BufferedReader。spa
import java.io.*; class MyBufferedReader { private FileReader r; MyBufferedReader(r) { this.r = r; } //能夠一次讀一行數據的方法。 public String myReadLine()throws IOException { //定義一個臨時容器,原BufferedReader封裝的是字符數組。 //爲了演示方便,定義一個StringBuilder容器,由於還要將數據變成字符串。 StringBuilder sb = new StringBuilder(); int ch = 0; while((ch=r.read())!=-1) { if(ch=='\r') continue; if(ch=='\n') return sb.toString(); else sb.append((char)ch); } if(sb.length()!=0) return sb.toString(); return null; } pubilc void myClose()throws IOException { r.close(); } } class MyBufferedReaderDemo { public static void main(String[] args)throws IOException { FileReader fr = new FileReader("buf.txt"); MyBufferedReader myBuf = new MyBufferedReader(fr); String line = null; while((line = myReadLine())!=null) { System.out.println(line); } muBuf.mtClose(); } }
由上述例子可見,readLine()方法是在加強read()方法,經過將被加強的對象傳給加強類,提供了一個基於它的讀一行的方法,MyBufferedReader其實就是在對FlieReader進行加強,那麼這種方式咱們也把它稱之爲一種設計模式,叫作裝飾設計模式。 設計
裝飾設計模式:當想要對已有對象進行功能加強時,能夠定義類,將已有對象傳入,基於已有功能,並提供增強功能,那麼自定義的該類稱爲裝飾類。
裝飾類一般會經過構造方法接收被裝飾對象並基於被裝飾的對象的功能,提供更強的功能。
class Person { public void chifan() { Systam.out.println("吃飯"); } } class SuperPerson { private Person p; SuperPerson(Person P) { this.p = p; } public void superChifan() { Systam.out.println("開胃酒"); p.chifan(); Systam.out.println("甜點"); Systam.out.println("來一根"); } } class PersonDemo { public static void main(String[] args) { Person p = new Person(); SuperPerson sp = new SuperPerson(p); sp.superChifan(); } }
MyReader//專門用於讀取數據的類。
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
|--MyDateReader
|--MyBufferDateReader
繼承體系雖然能用,可是擴展性很是很差,體系臃腫。須要進行優化,發行着三個類擴展出來的都是同一種技術,因此單獨定義一個緩衝類MyBufferReader。
class MyBufferReader
{
MyBufferReader(MyTextReader text)
{}
MyBufferReader(MyMediaReader media)
{}
}
上面這個類擴展性不好,找到其參數的共同類型,經過多態的形式,能夠提升擴展性。
class MyBufferReader extends MyReader
{
private MyReader r ;
MyBufferReader(MyReader r)
{
this.r = r;
}
}
優化後體系:
MyReader
|--MyTextReader
|--MyMediaReader
|--MyDateReader
|--MyBufferReader
裝飾模式比繼承要靈活,避免了繼承體系臃腫,並且下降了類與類之間的關係。
裝飾類由於加強已有對象,具有的功能和已有的是相同的,只不過提供了更強的功能,因此裝飾類和被裝飾類一般都是屬於同一個體系中。(所屬同一個父類或者同一個接口)
import java.io.*; class MyBufferedReader extends Reader { private Reader r; MyBufferedReader(Reader r) { this.r = r; } //能夠一次讀一行數據的方法。 public String myReadLine()throws IOException { //定義一個臨時容器,原BufferedReader封裝的是字符數組。 //爲了演示方便,定義一個StringBuilder容器,由於還要將數據變成字符串。 StringBuilder sb = new StringBuilder(); int ch = 0; while((ch=r.read())!=-1) { if(ch=='\r') continue; if(ch=='\n') return sb.toString(); else sb.append((char)ch); } if(sb.length()!=0) return sb.toString(); return null; } //覆蓋Reader類中的抽象方法。 public int read(char[] cbuf,int off,int len)throws IOException { r.read(cbuf,off,len); } public void close()throws IOException { r.close(); } pubilc void myClose()throws IOException { r.close(); } } class MyBufferedReaderDemo { public static void main(String[] args)throws IOException { FileReader fr = new FileReader("buf.txt"); MyBufferedReader myBuf = new MyBufferedReader(fr); String line = null; while((line = myReadLine())!=null) { System.out.println(line); } muBuf.mtClose(); } }
LineNumberReader:跟蹤行號的緩衝字符輸入流。此類定義了方法 setLineNumber(int)
和 getLineNumber()
,它們可分別用於設置和獲取當前行號。
import java.io.*; class LineNumberReaderDemo { publiv static void main(String[] args)throws IOException { FileReader fr = new FileReader("PersonDemo.java"); LineNumberReader lnr = new LineNumberReader(fr); String line = null; lnr.setLineNumber(100); while((line= lnr.readline())!=null) { System.out.println(lnr.getLineNumber+":"+line); } lnr.close(); } }
練習:模擬一個帶行號的緩衝區對象。
import java.io.*; class MyLineNumberReader extends myBufferedReader { private int lineNumber; MyLineNumberReader(Reader r) { super(r); } public String myReadline() { lineNumber++; super myReadLine(); } public int setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } public int getLineNumber() { return lineNumber; } } /* class MyLineNumberReader { private Reader r; private int lineNumber; MyLineNumberReader(Reader r) { this.r = r; } public String myReadline() { lineNumber++; StringBuilder sb = new StringBuilder(); int ch = 0; while((ch = r.read())!-1) { if(ch=='\r') continue; if(ch=='\n') return sb.toString(); else sb.append((char)ch); } if(sb.length()!= 0) return sb.toString(); return null; } public int setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } public int getLineNumber() { return lineNumber; } public void myClose() { r.close(); } } */ class MyLineNumberReaderDemo { public static void main(String[] args)throws IOException { FileReader fr = new FileReader("copyTextByBuf.java) MyLIneNumberReader mylnr = new MyLIneNumberReader(fr); Stirng line = null; mylnr.setLineNumber(100); while((line = mylnr.myReadLine())!null) { System.out.println(mylnr.getLineNumber+"::"+line); } mylnr.myClose(); } }
。。。。。。