BufferedReader和BufferedWriter分别是Reader和Writer的直接子类。他们称为字符流的缓冲区。
BufferedInputStream和BufferedOutputStream分别是FilterInputStream的直接子类FilterOutputStream,他们称为字节流的缓冲区。
缓冲区的出现提高了流对数据的读写效率。缓冲区是为流服务的谁在创建缓冲区之前必须流对象。
BufferedReader中的特殊方法:
public void newLine()写入一个行分隔符
BufferedWriter中的特殊方法:
public String readLine()读入一个文本行,并以字符串返回。
此方法可以用来作为循环结束的条件readLine()!=null,等于空时表示已读到文件尾了,之一此方法读取一行后返回的String不包含回车符
此方法的原理:无论是读一行或者读取多个字节,其实最终都是在硬盘上一个一个的读取,所以最终使用的还是read()方法此方法只是在内存中开辟了一个数组,并将每次读取的数据存入此数组,当读到’\r’,’\n’时,表示该行结束,此时将此数组转成String返回,方法就结束了。Readline方把’\r’,’\n’作为行的结束,并且不会读取。
装饰设计模式:
但想要对一个已有类的功能进行增强,可以定义类,将已有类的对象传入,基于已有的功能,并提供加强功能,那么,自定义类称为装饰类。装饰类通常会通过构造方法接收被装饰类的对象,并基于被装饰类的功能提供更强大的功能。
装饰和继承的区别:
装饰模式要比继承灵活,避免了继承的臃肿。而且降低了类与类之间的关系。
装饰类因为增强已有类的功能,几倍的功能和已有功能相同,只不过提供了更强大的功能。所以装饰类和被装饰类通常都是输同一个体系的,结成统一个类或者接口,这种结构称为组合结构(装饰模式将继承转成组合结构)。
需求:1.自定义一个字符流的缓冲区,更BufferedReader具备相同的工能即ReadLIne方法
/*
自定义一个缓冲流类与BufferedReader具有相似功能
装饰模式的应用
*/
import java.io.*;
class MyBufferedReaderextends Reader {
private FileReader fr;
public MyBufferedReader(FileReader fr)throws IOException{
this.fr = fr;
}
public String MyReadLine()throws IOException{
int x = 0;
StringBuilder sb = new StringBuilder();
while((x = fr.read()) != -1){
if(x == '\n' || x == '\r'){
return sb.toString();
}else{
sb.append((char)x);
}
}
if(x == -1)
return null;
return sb.toString();
}
public void close()throws IOException{
fr.close();
}
public int read(char[] cbuf,int off,int len)throws IOException{
return fr.read(cbuf,off,len);
}
}
class MyBufferedReaderDemo{
public static void main(String[] args)throws IOException{
MyBufferedReader mbr = new MyBufferedReader(new FileReader("MyBufferedReaderDemo.java"));
String str = null;
while((str = mbr.MyReadLine()) != null){
System.out.println(str);
}
mbr.close();
}
}
LineNumberReader是BufferedReade的直接子类,特有方法 public int getLineNumber()获得当前行号。
public void setLineNumber(int lineNumber)设置当前行号。如果不设置的话,默认从0开始,设置的是几就从几开始
需求:2.自定义一个字符流,LineNumberReader具备相同的工能即ReadLIne方法
/* 模拟一个带行号的缓冲区 优化改进后的 */ import java.io.*; class MyLineNumberReader extends MyBufferedReader{ private int lineNumber = 0; public MyLineNumberReader(FileReader fr)throws IOException{ super(fr); } public String MyReadLine()throws IOException{ lineNumber++; return super.MyReadLine(); } //获得当前行号。 public int getLineNumber(){ return lineNumber; } //设置当前行号。 public void setLineNumber(int lineNumber){ this.lineNumber = lineNumber; } } class MyLineNumberReaderDemo1{ public static void main(String[] args){ MyLineNumberReader lnbr = null; try{ //建立一个行号造作流,并传入一个流对象 lnbr = new MyLineNumberReader(new FileReader("LineNumberReaderDemo.java")); String str = null; lnbr.setLineNumber(5);//设置起始行号,默认是从1开始 while((str = lnbr.MyReadLine()) != null){ //获得行号并打印行号 System.out.println(lnbr.getLineNumber()+ "::"+str); } }catch(FileNotFoundException e){ throw new RuntimeException(" can mot found file"); }catch(IOException e){ throw new RuntimeException(" read fail"); }finally{ try{ if(lnbr != null) lnbr.close();//关闭流资源 }catch(IOException e){ } } } }
字节流在read和write是的特点read()方法每次读取的是一个字节但返回的却是一个Int的数据,所以此方法byte进行过了类型提升,而write(int)方法只是将int型的低八位写入。
在用键盘录入时,为什么只录入一个字符会打印三个值呢?
因为有回车符:“\r\n”,’\r’=13, ’\n’=10
在用键盘录入时,发现其实就是读一行的原理。那么能不能用ReadLIne方法来完成键盘的录入呢?readerLine是字符流BufferedReader的方法,而标准输出流是字节流,所以此时要用到转换流。InputStreamReader 和。InputStreamReader是Reader和Writer的直接子类
BufferedReader in =
New BufferedReader(new InputStreamReader(System.in));
Writer out
= new BufferedWriter(new OutputStreamWriter(System.out));
那么什么时候使用转换流呢?
转换流是字符流和字节流之间的桥梁,通常涉及到字符编码的时候,
需要用到转换流
System类中的静态方法
public static void setIn(InputStream in)
和
public static void setOut(PrintStream out)
可以让我们自己设定标准输入输出流