字符流的缓冲区
- 缓冲区的出现提高了对数据的读写效率。
- 对应类:
- BufferedWriter
- BufferedReader
- 缓冲区要结合流才可以使用。
- 在流的基础上对流的功能进行了增强。
BufferedWriter
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
缓冲区的出现是为了提高流的操作效率而出现的。所以在创建缓冲区之前,必须要先有流对象。
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(); }}
BufferedReader
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
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方法返回的时候只返回回车符之前的数据内容。并不返回回车符。
readLine方法原理:无论是读一行,获取读取多个字符,其实最终都是在硬盘上一个一个读取,所以最终使用的还是read方法,一次读一个的方法。
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("写入关闭失败"); } } } }}
myBufferedReader
明白了BufferedReader类中特有方法readLine的原理后,可以自定义一个类中包含一个功能和readLine一致的方法。来模拟一下BufferedReader。
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装饰类
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(); }}
练习:模拟一个带行号的缓冲区对象。
MyLIneNumberReader
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(); }}
。。。。。。