学习目标:掌握具有缓存的输入和输出流。
支持缓存的输入与输出流
BufferedInputStream为带缓存的输入流,BufferedOutputStream为带缓存的输出流。缓存输入输出就是在读写磁盘文件之前,先把数据读取或写入到预先分配的内存区域(这片内存区域称为缓冲区),当缓冲区存储的数据已满时,再进行磁盘文件的读写操作。通过缓冲区读写文件带来的好处是可以优化程序的输入输出性能,提高程序读写磁盘文件的速度。
BufferedInputStream类的工作依赖于InputStream,它需要使用InputStream类进行磁盘文件的读写。BufferedInputStream读取文件的工作原理如下图所示:

BufferedInputStream类在内部维护一个缓冲区。实例化BufferedInputStream对象时,需要传入InputStream的实例化对象,当程序调用BufferedInputStream对象从文件读取数据时,它会先判断缓冲区是否有读取的文件数据,如果有就从缓冲区读取,否则就调用InputStream对象从文件读取数据填满缓冲区。
BufferedOutputStream类和BufferedInputStream类的工作原理是相同的,只不过一个是写入文件数据,一个是读取文件数据。BufferedOutputStream类在内部也维护一个缓冲区,当程序调用BufferedOutputStream将数据写入文件时,它会先把数据写入缓冲区,当缓冲区已满时,再调用OutputStream将缓冲区的数据写入到文件。BufferedOutputStream类也提供了flush()方法,可以强制将缓冲区的数据写入到文件。
(1)BufferedInputStream类
BufferedInputStream类有默认的缓冲区空间,程序可以在类的构造函数中传入需要的缓冲区空间大小。
BufferedInputStream类的构造函数如下:
● public BufferedInputStream(InputStream in);
该构造函数创建具有默认缓冲区空间的输入流。
● public BufferedInputStream(InputStream in, int size);
该构造函数创建指定缓冲区空间大小的输入流。
InputStream类是BufferedInputStream的父类,因此InputStream类定义的方法,BufferedInputStream都可以使用。
案例15:建立BufferedInputStreamTest测试类,读取图片文件。
在PUnit11项目新建buffer包,在buffer包下新建BufferedInputStreamTest类。代码如下:
package buffer;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class BufferedInputStreamTest {
public static void main(String[] args) {
// 读取的图片文件路径
String filename = "d:\\001.jpg";
BufferedInputStream bufferedInput = null;
// 申请读取文件的缓冲区
byte[] buffer = new byte[1024];
try {
// 创建BufferedInputStream 对象
bufferedInput = new BufferedInputStream(new FileInputStream(filename));
int bytesRead = 0;
// 从文件中按字节读取内容,到文件尾部时read方法将返回-1
while ((bytesRead = bufferedInput.read(buffer)) != -1) {
// 将读取的字节转为字符串对象
String content = new String(buffer, 0, bytesRead);
System.out.print(content);
}
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
// 关闭 BufferedInputStream
try {
if (bufferedInput != null)
bufferedInput.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
案例代码完成读取图片文件的操作,使用BufferedInputStream类的read方法将图片文件数据读入到buffer缓冲区,并将buffer缓冲区的输出到控制台。因为读取的图片文件是二进制文件,所以在控制台显示的是乱码。关闭文件放到了finally语句块,这样做的好处是不管是否发生文件读取异常,都会关闭已打开的文件资源。
(2)BufferedOutputStream类
BufferedOutputStream类有默认的缓冲区空间,程序可以在类的构造函数中传入需要的缓冲区空间大小。BufferedOutputStream类的构造函数如下:
● public BufferedOutputStream(OutputStream out);
该构造函数创建具有默认缓冲区空间的输出流。
● BufferedOutputStream(OutputStream out, int size);
该构造函数创建指定缓冲区空间大小的输出流。
OutputStream类是BufferedOutputStream的父类,因此OutputStream类定义的方法,BufferedOutputStream都可以使用。
案例16:建立BufferedOutputStreamTest测试类,建立一个二进制文件,输出数据到新建的二进制文件。
在buffer包下新建BufferedOutputStrea
package buffer;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferedOutputStreamTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
BufferedOutputStream bufferoutput = null;
//写数据
try {
bufferoutput = new BufferedOutputStream(new FileOutputStream("d:\\outtest.dat")) ;
// 将String对象的内容转换为字节数组,并写入文件
bufferoutput.write("这是一个二进制文件".getBytes());
System.out.println("文件创建成功");
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("文件创建失败");
e.printStackTrace();
} finally {
//释放资源
try {
bufferoutput.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
案例代码创建一个二进制文件,并写入字符串对象的内容。虽然创建的是二进制文件,但使用记事本仍然可以看到写入的中文内容,因为新建的二进制文件存储的是中文内容的文字编码。
文本缓存输入类
BufferedReader类是文本缓存输入类,BufferedReader类的父类是Reader类,BufferedReader类具有缓存机制,工作原理和BufferedInputStream类相同。
BufferedReader类有默认的缓冲区空间,程序可以在类的构造函数中传入需要的缓冲区空间大小。
BufferedReader类的构造函数如下:
● public BufferedReader(Reader in);
该构造函数创建具有默认缓冲区空间的文本输入流。
● public BufferedReader(Reader in, int sz)
该构造函数创建指定缓冲区空间大小的文本输入流。
Reader类的方法在《输入输出流》一课中已介绍,BufferedReader类新增加了一个readLine()方法,该方法说明如下:
● String readLine()
该方法从文本文件中读取一行数据。
案例17:建立BufferedReaderTest测试类,使用BufferedReader的readLine()方法按行读取文本文件。
在buffer包下新建BufferedReaderTest类。代码如下:
package buffer;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderTest {
public static void main(String[] args) {
// 读取的文本文件路径
String filename = "d:\\sample1.txt";
BufferedReader reader;
String line;
try {
// 实例化BufferedReader对象
reader = new BufferedReader(new FileReader(filename));
// 按行读取
while ((line = reader.readLine()) != null) {
System.out.print(line + "\n");
}
// 关闭文件
reader.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
案例代码使用BufferedReader类的readLine()方法按行读取文本文件,并输出到控制台。
文本缓存输出类
BufferedWriter类是文本缓存输出类,BufferedWriter类的父类是Writer类,BufferedWriter类具有缓存机制,工作原理和BufferedOutputStream类相同。
BufferedWriter类有默认的缓冲区空间,程序可以在类的构造函数中传入需要的缓冲区空间大小。
BufferedWriter类的构造函数如下:
● public BufferedWriter(Writer out)
该构造函数创建具有默认缓冲区空间的文本输出流。
● public BufferedWriter(Writer out, int sz)
该构造函数创建指定缓冲区空间大小的文本输出流。
Writer类的方法在《输入输出流》一课中已介绍,BufferedWriter类新增加了一个newLine ()方法,该方法说明如下:
● String newLine ()
该方法输出一个换行符到文本文件。
案例18:建立BufferedWriterTest测试类,使用BufferedWriter的write ()和newLine()方法写入数据到文本文件。
在buffer包下新建BufferedWriterTest类。代码如下:
package buffer;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWriterTest {
public static void main(String[] args) {
String filename = "d:\\poetry.txt";
BufferedWriter bufferwriter = null;
try {
bufferwriter = new BufferedWriter(new FileWriter(filename));
bufferwriter.write("故人西辞黄鹤楼,");
// 写入换行符
bufferwriter.newLine();
bufferwriter.write("烟花三月下扬州。");
// 写入换行符
bufferwriter.newLine();
bufferwriter.write("孤帆远影碧空尽,");
// 写入换行符
bufferwriter.newLine();
bufferwriter.write("唯见长江天际流。");
// 关闭流
bufferwriter.close();
System.out.println("文件写入成功");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
案例代码在D盘下创建poetry.txt文本文件,并写入李白的一首诗,每写入一句诗,就调用newLine()方法写入一个换行符到文本文件。