带缓存的输入/输出流

缓存是 I/O 的一种性能优化。缓存流为 I/O 流增加了内存缓存区,这使得在流上执行 skip()、mark() 和 reset() 方法都成为可能。

BufferedInputStream类和BufferedOutputStream类

BufferedInputStream 类可以对所有 InputStream 类进行带缓存区的包装以达到性能的优化。BufferedInputStream 类有以下两个构造方法:

  • BufferedInputStream(InputStream in)。

  • BufferedInputStream(InputStream in,int size)。

第一种形式的构造方法创建了一个有 32 个字节的缓存区,第二种形式的构造方法按指定的大小来创建缓存区。一个最优的缓存区的大小,取决于它所在的操作系统、可用的内存空间以及机器配置。从构造方法中可以看出,BufferedInputStream 对象位于 InputStream 类对象之后。图15.7描述了带缓存的字节流读取文件的过程。

使用 BufferedOutputStream 类输出信息和仅用 OutputStream 类输出信息完全一样,只不过 BufferedOutputStream 类有一个 flush() 方法用来将缓存区的数据强制输出完。BufferedOutputStream 类也有两个构造方法:

image 2024 03 05 17 25 54 401
Figure 1. 图15.7 BufferedInputStream读取文件的过程
  • BufferedOutputStream(OutputStream in)。

  • BufferedOutputStream(OutputStream in,int size)。

第一种构造方法创建一个有 32 个字节的缓存区,第二种构造方法以指定的大小来创建缓存区。

flush() 方法就是用于即使在缓存区没有满的情况下,也将缓存区的内容强制写入外部设备中,习惯上称这个过程为刷新。flush() 方法只对使用缓存区的 OutputStream 类的子类有效。当调用 close() 方法时,系统在关闭流之前,也会将缓存区中的信息刷新到磁盘文件中。

BufferedReader类和BufferedWriter类

BufferedReader 类与 BufferedWriter 类分别继承 Reader 类与 Writer 类。这两个类同样具有内部缓存机制,并能够以行为单位进行输入/输出。

根据 BufferedReader 类的特点,可以总结出如图15.8所示的带缓存的字符数据读取文件的过程。

image 2024 03 05 17 28 57 953
Figure 2. 图15.8 BufferedReader类读取文件的过程

BufferedReader 类常用的方法如下。

  • read() 方法:读取单个字符。

  • readLine() 方法:读取一个文本行,并将其返回为字符串。若无数据可读,则返回 null。

BufferedWriter 类中的方法都返回 void。常用的方法如下:

  • write(String s, int off, int len) 方法:写入字符串的某一部分。

  • flush() 方法:刷新该流的缓存。

  • newLine() 方法:写入一个行分隔符。

在使用 BufferedWriter 类的 Write() 方法时,数据并没有立刻被写入输出流中,而是首先进入缓存区中。如果想立刻将缓存区中的数据写入输出流中,则一定要调用 flush() 方法。

【例15.5】使用缓冲流读写文本文件(实例位置:资源包\TM\sl\15\5)

使用 BufferedReader 类和 BufferedWriter 类,向 D 盘根目录下的 word.txt 文件中写入多行内容,然后将其读取出来输出到控制台上。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedDemo {
	public static void main(String args[]) {
		String content[] = { "好久不见", "最近好吗", "常联系" };// 写入的内容
		File file = new File("D:\\word.txt"); // 创建文件对象
		try {
			FileWriter fw = new FileWriter(file); // 文件字符输出流
			BufferedWriter bw = new BufferedWriter(fw); // 换成输出流
			for (int k = 0; k < content.length; k++) { // 遍历要输入的内容
				bw.write(content[k]); // 写入字符串
				bw.newLine(); // 写入一个换行符
			}
			bw.close(); // 关闭缓冲输出流
			fw.close(); // 关闭文件字符输出流
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			FileReader fr = new FileReader(file); // 文件字符输入流
			BufferedReader br = new BufferedReader(fr);// 缓冲输入流
			String tmp = null; // 作为缓冲的临时字符串
			int i = 1; // 行数
			// 从文件中读出一行,如果读出的内容不为null,则进入循环
			while ((tmp = br.readLine()) != null) {
				System.out.println("第" + i + "行:" + tmp); // 输出读取的内容
				i++; // 行数递增
			}
			br.close(); // 关闭缓冲输入流
			fr.close(); // 关闭文件字符输入流
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

程序运行之后会向 D 盘根目录下的 word.txt 文件中写入3行文字,并且会在控制台输出如下信息:

     第1行:好久不见
     第2行:最近好吗
     第3行:常联系

编程训练(答案位置:资源包\TM\sl\15\编程训练)

【训练5】记录《再别康桥》 将徐志摩的《再别康桥》全文写入D盘根目录下的word.txt文件中。

【训练6】从文件中读取《再别康桥》 将训练5中写入的内容全部输出到控制台中。