Java:IO流之字符流缓冲区详解
字符流缓冲区:
1、缓冲区的出现提高了对数据的读写效率;
2、对应类:BufferedWriter、BufferedReader;
3、缓冲区要结合流才可以使用;
4、在流的基础上对流的功能进行了增强。
注意:缓冲区的出现是为了提高流的操作效率而出现的,所以在创建缓冲区之前必须现有流对象。
java.io
类 BufferedReader:读入缓冲区
构造方法摘要
BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int sz) 创建一个使用指定大小输入缓冲区的缓冲字符输入流。
主要方法摘要
void close() 关闭该流并释放与之关联的所有资源。
int read() 作为一个整数(其范围从0到65535(0x00-0xffff)读入的字符,如果已到达流末尾,则返回 -1,读取单个字符。
int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。
String readLine() //包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null ,读取一个文本行。
//例子1:
import java.io.*; class BufferedReaderDemo { public static void main(String[] args) throws IOException { //创建一个字符读入流对象,和目的地文件相关联. FileReader fr = new FileReader("F:\\myfile\\buf.txt"); //为了提高字符读入流效率,加入了缓冲技术,只需要将被提高效率的流对象作为参数 //传递给缓冲区的构造函数即可。此时,缓冲区和流相关联. BufferedReader buf = new BufferedReader(fr); int num = 0; String line = null; /* while((line = buf.readLine())!=null) //此过程中,读入缓冲区一行一行的读取数据,效率高 { System.out.println(line); } */ while((num = buf.read())!=-1) { System.out.print((char)num); } //其实关闭缓冲区,就是关闭缓冲区中的流对象 buf.close(); } }
readLine方法的原理:尽管是读取一行获取多个字符,其实最终都是在硬盘上一个一个地读取字符。所以最终使用的还是read方法一次读一个的方法。
明白了BufferedReader类中特有方法readLine的原理后,
可以自定义一个类中包含一个功能和readLine一致的方法,
来模拟一个BufferedReader
(该代码中的思想体现了装饰设计模式)
//例子2:
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) //出现读取一行数据到了缓冲区,但是该字符串后面没有'\n',可是仍要把它读取出来。 return sb.toString(); return null; } //覆盖Reader中的抽象方法 public int read(char[] cbuf, int off, int len) throws IOException { return r.(cbuf,off,len); } public void close()throws IOException { r.close(); } public void Myclose()throws IOException { r.close(); } }
//测试类 class MyBufferedReaderTest { public static void main(String[] args) { FileReader fr = null; MyBufferedReader mybuf = null; String line = null; try { mybuf = new MyBufferedReader(new FileReader("F:\\myfile\\buf.txt")); while((line = mybuf.MyreadLine())!=null) { System.out.println(line); } } catch(IOException e) { throw new RuntimeException("读入流异常"); } finally { try { mybuf.Myclose(); } catch(IOException e) { throw new RuntimeException("关闭流异常"); } } } }
自定义一个统计行号的类:MyLineNumberReader,可以设置复制得到的文件内容的行号
//例子3:
import java.io.*; /* class MyLineNumberReader extends MyBufferedReader { private int linenumber; MyLineNumberReader(Reader r) { super(r); } public void setLineNumber(int linenumber) { this.linenumber = linenumber; } public int getLineNumber() { return linenumber; } public String MyreadLine() throws IOException { linenumber++;//每读一行,行数就自加一次 return super.MyreadLine(); } } */ class MyLineNumberReader { private Reader r; private int linenumber; MyLineNumberReader(Reader r) { this.r = r; } public void setLineNumber(int linenumber) { this.linenumber = linenumber; } public int getLineNumber() { return linenumber; } public String MyreadLine() throws IOException { 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 void Myclose() throws IOException { r.close(); } } class MyLineNumberReaderDemo { public static void main(String[] args) { FileReader fr = null; MyLineNumberReader myl = null; String str = null; try { fr = new FileReader("MyBufferedReaderTest.java"); myl = new MyLineNumberReader(fr); //myl.setLineNumber(100); //设置第一行从101行开始 while((str = myl.MyreadLine())!=null) { System.out.println(myl.getLineNumber()+":"+str); } } catch(IOException e) { System.out.println("流读入异常!"); } finally { try { myl.Myclose(); } catch(IOException e) { System.out.println("流关闭异常!"); } } } }
java.io
类 BufferedWriter:写入缓冲区
构造方法摘要
BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。
BufferedWriter(Writer out, int sz) 创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
方法摘要
void close() 关闭此流,但要先刷新它。
void flush() 刷新该流的缓冲。
void newLine() 写入一个行分隔符。具有跨平台性,相当于windows系统的"\r\n"和linux系统的"\n";
void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。
void write(int c) 写入单个字符。
void write(String s, int off, int len) 写入字符串的某一部分。
//例子4:
import java.io.*; class BufferedWriterDemo { public static void main(String[] args) throws IOException { //创建一个字符写入流对象,和目的地文件相关联. FileWriter fw = new FileWriter("F:\\myfile\\buf.txt"); //为了提高字符写入流效率,加入了缓冲技术,只需要将被提高效率的流对象作为参数 //传递给缓冲区的构造函数即可。此时,缓冲区和流相关联. BufferedWriter buf = new BufferedWriter(fw); buf.write("abcdefg"); for(int i=0;i<3;i++) { buf.newLine();//换行 buf.write("changjiang"+i); //记住,只要用到缓冲区,必须要刷新 buf.flush(); } //其实关闭缓冲区,就是关闭缓冲区中的流对象 buf.close(); } }
使用字符流缓冲的一个综合实例如下:
要求:通过一个缓冲区复制一个.java文件
注意:readLine()方法返回的时候只返回回车符之前的数据内容,并不返回回车符。
//例子5: 没有异常处理时:
import java.io.*; class BufferedCopyTest { public static void main(String[] args)throws IOException { //创建一个读入流对象,与要被复制的文件相关联 FileReader fr = new FileReader("BufferedReaderDemo.java"); //创建一个写入流对象,与目的文件相关联 FileWriter fw = new FileWriter("BufferedReaderDemo_Copy.txt"); //创建一个读入缓冲区,与流对象相关联 BufferedReader bufr = new BufferedReader(fr); //创建一个写入缓冲区,与流对象相关联 BufferedWriter bufw = new BufferedWriter(fw); //读取数据存入缓冲区中 String line; while((line = bufr.readLine())!=null) { bufw.write(line); bufw.newLine(); bufw.flush(); } bufw.close(); bufr.close(); } }
//例子6: 有异常的处理时:
import java.io.*; class BufferedCopyTest2 { public static void main(String[] args) { BufferedReader bufr = null; BufferedWriter bufw = null; try { bufr = new BufferedReader(new FileReader("BufferedReaderDemo.java")); bufw = new BufferedWriter(new FileWriter("BufferedReader_Copy.txt")); String line; while((line = bufr.readLine())!=null) { System.out.println(line); 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("关闭流异常"); } } } }
程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式!