java--IO流缓冲区,装饰设计模式

时间:2021-01-18 21:35:58

缓冲区的出现是为了提高流的操作效率而出现的。

所以在创建缓冲区之前,必须要先有流对象。

对应类:BufferedWriter,BufferedReader。BufferedInputStream,BufferedOutputStream。

缓冲区结合流才可以使用。
在流的基础上对流的功能进行了增强。

BufferedWriter:字符输出流缓冲区

该缓冲区中提供了一个跨平台的换行符。
newLine();

import java.io.*;
class Test
{
public static void main(String[] args) throws IOException
{
//创建一个字符写入流对象。
FileWriter fw = new FileWriter("buf.txt");

//为了提高字符写入流效率。加入了缓冲技术。
//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
BufferedWriter bufw = new BufferedWriter(fw);

for(int x=1; x<5; x++)
{
bufw.write("abcd"+x);
bufw.newLine();
bufw.flush();//刷新一次缓冲区对文件写入一次
}

//记住,只要用到缓冲区,就要记得刷新。
//bufw.flush();

//其实关闭缓冲区,就是在关闭缓冲区中的流对象。
bufw.close();
}
}
字符读取流缓冲区:
该缓冲区提供了一个一次读一行的方法 readLine,方便于对文本数据的获取。
当返回null时,表示读到文件末尾。
readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。

import java.io.*;
class Test
{
public static void main(String[] args) throws IOException
{
//创建一个读取流对象和文件相关联。
FileReader fr = new FileReader("buf.txt");

//为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。
BufferedReader bufr = new BufferedReader(fr);

String line = null;
while((line=bufr.readLine())!=null)
{
System.out.println(line);
}
bufr.close();
}
}

通过缓冲区复制一个文件:

import java.io.*;
class CopyTextByBuf
{
public static void main(String[] args)
{
BufferedReader bufr = null;
BufferedWriter bufw = null;
try
{
bufr = new BufferedReader(new FileReader("buf.txt"));
bufw = new BufferedWriter(new FileWriter("buf1.txt"));
String line = null;
while((line=bufr.readLine())!=null)
{
bufw.write(line);
bufw.newLine();
bufw.flush();
}
}
catch (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("写入关闭失败");}
}
}
}
装饰设计模式:
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类称为装饰类。
装饰类通常会通过构造方法接收被装饰的对象。并基于被装饰的对象的功能,提供更强的功能。

class Person
{
public void chifan()
{
System.out.println("吃饭");
}
}
class SuperPerson //对Person功能的增强
{
private Person p ;
SuperPerson(Person p)
{
this.p = p;
}
public void superChifan()
{
System.out.println("开胃酒");
p.chifan();
System.out.println("甜点");
System.out.println("来一根");
}
}
class PersonDemo
{
public static void main(String[] args)
{
Person p = new Person();
//p.chifan();
SuperPerson sp = new SuperPerson(p);
sp.superChifan();
}
}

装饰和继承的区别:

例如:

MyReader //创建一个类专门用于读取数据的类。
|--MyTextReader//对文本的读取
|--MyBufferTextReader//利用缓冲技术对文本的读取
|--MyMediaReader //对媒体的读取
|--MyBufferMediaReader //利用缓冲技术对媒体的读取
|--MyDataReader//对数据的读取
|--MyBufferDataReader //利用缓冲技术对数据的读取
那么可以这样定义:
class MyBufferReader
{
MyBufferReader(MyTextReader text)
{}
MyBufferReader(MyMediaReader media)
{}
}
上面这个类扩展性很差。
找到其参数的共同类型。通过多态的形式。可以提高扩展性。
class MyBufferReader extends MyReader
{
private MyReader r;
MyBufferReader(MyReader r)
{}
}
这样的话,可以获得的继承体系为:
MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferReader

结论:
以前是通过继承将每一个子类都具备缓冲功能。那么继承体系会复杂,并不利于扩展。

现在优化思想。单独描述一下缓冲内容。将需要被缓冲的对象。传递进来。也就是,谁需要被缓冲,谁就作为参数传递给缓冲区。这样继承体系就变得很简单。优化了体系结构。

装饰模式比继承要灵活。避免了继承体系臃肿。而且降低了类于类之间的关系。

装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。所以装饰类和被装饰类通常是都属于一个体系中的。

自定义装饰类:

class MyBufferedReader extends Reader
{
private Reader r;
MyBufferedReader(Reader r)
{
this.r = r;
}

//可以一次读一行数据的方法。
public String myReadLine()throws IOException
{
//定义一个临时容器。原BufferReader封装的是字符数组。
//为了演示方便。定义一个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
{
return r.read(cbuf,off,len) ;
}

public void close()throws IOException
{
r.close();
}
}
LineNumberReader类:一个带行号的装饰类。