(83)BufferedWriter、BufferedReader增强读写、装饰模式
缓冲区的出现提高了对数据的读写效率
缓冲区理解成杯子:将每一滴水,装入杯子,然后满了再用
一、 BufferedWriter:
①将文本写入字符输出流,缓冲各个字符,从而提高单个字符、数组和字符串的高效写入。
② 缓冲区的出现时为了提高流的操作效率而出现的,所以在创建缓冲区之前,必须先有流对象
③该缓冲区中提供了一个跨平台的换行符,newLine();[有缓冲区对象,才能用此方法]
public static void main(String[] args)throws IOException {
//创建一个字符写入流对象
FileWriter fw=new FileWriter("demo.txt");
//为了提高字符写入流效率,加入了缓冲技术,
//只要将需要提高效率的流对象作为参数传递给缓冲区的构造函数即可
BufferedWriter bufw=new BufferedWriter(fw);
bufw.write("abcde");
bufw.newLine();//行分割,因为不同系统的换行符不同,通过这个方法,就可以实现跨平台性
bufw.write("hello");
//记住只要用到缓冲区,就得刷新
bufw.flush();
//其实关闭缓冲区,就是关闭缓冲区中的流对象,不用再写fw.close();
bufw.close();
}
二、BufferedReader
public String readLine() throws IOException
作用:读取一个文本行,方便于对文本数据的读取
返回:包含该行的字符串,不包含任何行终止符(只返回回车符前的内容),如果到达流的末尾,则返回null[循环条件]
public static void main(String[] args)throws IOException {
//创建一个读取流对象和文件相关联
FileReader fr=new FileReader("Demo.java");
//为了提高效率,加入缓冲技术,
//将字符读取对象作为参数传递给缓冲区的构造函数
BufferedReader bufr=new BufferedReader(fr);
String line=null;
while((line=bufr.readLine())!=null)
System.out.println(line);
}
文件复制在缓冲区中代码写法
两个流中的中转站是line
public class Demo7 {
public static void main(String[] args) {
FileWriter fw=null;
FileReader fr=null;
BufferedWriter bufw=null;
BufferedReader bufr=null;
try {
fw=new FileWriter("E:\\Demo.java");
fr=new FileReader("C:\\Demo.java");
bufw=new BufferedWriter(fw);
bufr=new BufferedReader(fr);
String line=null;
while((line=bufr.readLine())!=null) {
bufw.write(line);
bufw.newLine();
bufw.flush();
}
}catch(IOException e) {
throw new RuntimeException("读取失败");
}
finally {
try {
if(bufw!=null)
bufw.close();
}catch(IOException e) {
throw new RuntimeException("关闭失败");
}
try {
if(bufr!=null)
bufr.close();
}catch(IOException e) {
throw new RuntimeException("关闭失败");
}
}
}
}
三、readLine原理
import java.io.*;
/*
* 明白了BufferedReader类中特有方法readlin的原理后,
* 可以自定义一个类中包含一个功能和readerLine相同的方法
* 来模拟BufferedReader
*/
public class MyBufferedReader {
private FileReader r;
//功能:可以一次读一行数据
public String myReaderLine()throws IOException {
//定义一个临时容器,原BufferedReader封装的是字符数组
//为了方便演示,定义一个StringBuffer容器,因为最终还是要将数据变成字符串
StringBuilder sb=new StringBuilder();
int ch=0;//在内部还是一个字符一个字符的读read(),只是先将其放入缓冲区中,到一行结束才读出或者输出
while((ch=r.read())!=-1) {
if(ch=='\r')//"\r\n"是换行,若只是\r不一定换行
continue;
if(ch=='\n')
return sb.toString();
sb.append((char)ch);
}
if(sb.length()!=0) //最后一行可能没有换行字符,但是也写入sb中,所以要输出,否则会缺少一行
return sb.toString();
return null;//while中已经将文本读完了,所以返回空
}
public void myClose()throws IOException {
r.close();
}
}
调用:
public class MysbDemo {
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
FileReader fr=new FileReader("Demo.txt");
MyBufferedReader myBuf=new MyBufferedReader(fr);
String line=null;
while((line=myBuf.myReaderLine())!=null) {
System.out.println(line);
}
myBuf.myClose();
}
}
装饰设计模式:
当想要对已有的对象进行功能增强,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能.
装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
bufferReader也是这样,在FileReader类中的read()也可以读数据,只是一个读的,而BufferReader中也是读数据,它基于一个一个读的基础上读读一行数据
通过简单例子:同是吃饭,增强吃饭功能
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("甜点");
}
}
调用:
Person p=new Person();
SuperPerson sp=new SuperPerson(p);
装饰设计模式由来详细说明:
Reader//专门用于读取数据
其实这些Buffer都是加强数据的读取,所以可以抽取一个类BufferReader,谁想加强,通过构造函数传入进来加强。
class BufferReader{
BufferReader(CharArrayReader cr){}
BufferReader(FilterReader cr){}
}
但是,这样又会造成问题,若Reader有新的子类进入体系,就得再加个构造函数,但是这样修改代码的形式是不提倡的,扩张性差,所以想到多态,任意子类传入都可以。
class BufferReader extendsReader {
BufferReader(Reader cr){}
}
注意到其最主要的也是读取,所以他也应该继承Reader,这样继承体系就放生了变化,如下形成装饰设计模式:
装饰模式继承更灵活,避免了继承体系的臃肿,而且降低了类与类之间的关系。
装饰类因为增强了已有对象,具备的功能和已有体系的是一样的,事不过提供了更强功能,所以装饰类和被装饰类通常是属于同一个体系中的
综上所述:MyBufferedReader就是个自定义装饰类,所以应该对其进行修改:
①继承Reader
②构造函数中的形参是Reader类型
③因为Reader是个抽象类,所以他的抽象方法必须得重写
1)在原有的代码中关闭MyClose是自定义方法,不属于重写,所以其函数名改为close
2)还得复写public abstract int read(char[] cbuf, int off, int len) throws IOException
也不知道怎么写,不过明确的是Reader的子类是必须实现这个方法的(否则还是抽象类),Reader直接子类InputStreamReader实现了这个方法,所以创建文件流对象可以直接用这个方法
可以这样写:
public int read(char[] cbuf, int off, int len) throws IOException
{
return r.read(cbuf, off, len)//可以用子类的实现方法即FileReader类中的方法,否则不能创建对象
}
重新改动后的代码如下:
package Demo;
import java.io.*;
public class MyBufferedReader extends Reader{
private FileReader r;
MyBufferedReader(FileReader r){
this.r=r;
}
public String myReaderLine()throws IOException {
StringBuilder sb=new StringBuilder();
int ch=0;
while((ch=r.read())!=-1) {
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}
public void close()throws IOException {
r.close();
}
public int read(char[] cbuf,int off,int len)throws IOException{
return r.read(cbuf, off, len);
}
}