将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。 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(); } }
。。。。。。