- 缓冲区的出现提高了对数据的读写效率
- 对应类:
- BufferedWriter
- BufferedReader
- 缓冲区需要结合流才可以使用, 对流的功能进行了增强, 即对流的操作起到装饰作用
使用缓冲区实现文本文件的写入和读取
// 写入public class BufferedWriterDemo{ public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("buf.txt"); // 为了提高写入的效率, 使用了字符流的缓冲区 // 创建了一个字符写入流的缓冲对象, 并和指定要被缓冲的流对象相关联 BufferedWriter bufw = new BufferedWriter(fw); // 使用缓冲区的写入方法将数据写入到缓冲区中 bufw.write("abcde"); // 换行, 其实就是封装了系统属性 line.separator // BufferedWriter 特有方法 bufw.newLine(); bufw.newline("hahaha"); // 使用缓冲区的刷新方法将数据刷入到目的地中 bufw.flush(); // 关闭缓冲区, 其实关闭的就是被缓冲的流对象 bufw.close(); }}// 读取public class BufferedReaderDemo { public static void main(String[] args){ FileReader fr = new FileReader("buf.txt"); BufferedReader bufr = new BufferedReader(); /* 读取字符数组的方式 * * char[] buf = new char[1024]; * int len = 0; * while((len=bufr.read(buf))!= -1){ * System.out.println(new String(buf,0,len)); * } */ // 按一行读取, BufferredReader 特有方法: readLine() // 如果到达流末尾, 返回 null String line = null; while((line=bufr.readLine()) != null){ // 注意: 此处判断的是 != null System.out.println(line); } // 关闭缓冲区 bufr.close(); }}
BufferedReader 中的 readLine() 方法原理
- BufferedReader 类复写了父类的以下方法:
- read(); : 读取单个字符
- read(char[] buf, int off, int len); : 读取数组的一部分
- BufferedReader 类自己特有的方法 readLine()
- BufferedReader 类继承了父类方法:
- read(char[] buf) : 将字符读入数组
readLine() 方法原理:
使用了读取缓冲区的 read() 方法, 将读取到的字符进行缓冲并判断换行标记. 将标记前的缓存数据变成字符返回.
模拟实现 BufferedReader
// 需求: 自定义的读取缓冲区, 其实就是模拟一个 BufferedReader/* 分析: * 缓冲区中无非就是封装了一个数组, 并对外提供了更多的方法对数组进行访问 * 其实这些方法最终操作的都是数组的角标 * * 缓冲区原理: 其实就是从源中获取一批数据装进缓冲区中, 在从缓冲区中不断 * 的取出一个一个数据. * * 在缓冲区中数据此次取完后, 在从源中继续取一批数据进缓冲区, 当源中的数据取光时, * 用 -1 作为结束标记 */ public class MyBufferedReader{ private FileReader r; // 定义一个数组作为缓冲区 private char[] buf = new char[1024]; // 定义一个指针用于操作这个数组中的元素, 当操作到最后一个元素时, 指针应该归 0 private int pos = 0; // 定义一个计数器, 记录缓冲区中的数据个数. 当该数据减到0, 就从源中继续获取数据到缓冲区中 private int count = 0; // 带参数的构造函数, 指定增强的流对象 public MyBufferedReader(FileReader r){ this.r = r; } // 定义从缓冲区读取单个字符的 read() 方法 public int myRead() throws IOException{ // 1. 从源中获取一批数据到缓冲区中, 需要先做判断, 只有计数器为 0 时, 才需要从源中获取数据 /* if(count == 0){ * // 记录从源中获取的数据个数 * count = r.read(buf); * if(count < 0){ * return -1; * } * // 每次从源中获取数据到缓冲区后, 角标归零 * pos = 0; * // 获取第一个数据 * char ch = buf[pos]; * pos++; * count--; * return ch; * } else { * char ch = buf[pos]; * pos++; * count--; * return ch; * } */ // 代码优化: if(count == 0){ count = r.read(buf); pos = 0; } if(count < 0){ return -1; } char ch = buf[pos++]; count--; return ch; } // 定义从缓冲区读取一行字符的 readLine() 方法 public String myReadLine() throws IOException{ // 定义一个数组容器, 存储从缓冲区中获取到的数据 StringBuilder sb = new StringBuilder(); // 使用自定义的 MyRead 方法, 从缓冲区中不断获取单个字符, int ch = 0; while((ch=myRead()) != -1){ if(ch=='\r') continue; if(ch=='\n') return sb.toString(); // 将从缓冲区中读到的字符, 存储到缓存行数据的缓冲区中 sb.append((char)ch); } // 如果最后一行结尾没有回车符, 缓冲区的读取已结束, // 但是并不能判断 if(ch=='\n'), 所有最后一行未能输出 if(sb.length() != 0) return sb.toString(); return null; } public void myClose() throws IOException{ r.close(); } }
使用缓冲区的方式复制文本文件
public class CopyTextByBufTest { public static void main(String[] args) throws IOException { FileReader fr = new FileReader("buf.txt"); BufferedReader bufr = new BufferedReader(fr); FileWriter fw = new FileWriter("buf_copy.txt"); BufferedWriter bufw = new BufferedWriter(fw); /* * int ch = 0; * // 使用缓冲区对象进行单个字符的读写 * // 这是直接从内存中读取单个字符, 不是从硬盘中 * while((ch=bufr.read()) != -1){ * bufw.write(ch); * } */ // 使用行进行读取文件 String line = null; while((line=bufr.readLine())!=null){ bufw.write(line); bufw.newLine(); bufw.flush(); // 注意: 每次写入之后, 进行刷新保存 } bufw.close(); bufr.close();}}
LineNumberReader 装饰类
- BufferedReader 的子类
- 可以跟踪行号的缓冲字符输入流
- setLineNumber(int); : 设置当前行号
- getLineNumber(); : 获取当前行号
参考资料