这篇来学习Java中利用缓存区来进行文件读写操作。一个输入流缓存(BufferedInputStream)和输出流缓存(BufferedOutputStream),理解了其中一个,另外一个就也理解了。下面,我们先看看BufferedInputStream这个类的API介绍和源码实现。
1.BufferedInputStream的原理
在这个类的API中,可以看到这么一句描述的话:在创建 BufferedInputStream
时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。那么,我们就看看它的底层实现原理。打开BufferedInputStrea源码,可以找到这么一个成员变量:
DEFAULT_BUFFER_SIZ=8192,这个表示缓冲区大小是8kb而且,底层是一个字节数组实现的。
2.BufferInputStream和BufferedOutputStream实现文件拷贝代码
我们直接来一个简单代码,然后来分析注意点和总结特点。
package io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo4_BufferCopy {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("C:\\Users\\Administrator\\Desktop\\jenkins.war");
FileOutputStream fos = new FileOutputStream("copy.war");
//创建缓冲区,对输入流进行包装
BufferedInputStream bis = new BufferedInputStream(fis);
//创建缓冲区,对输出流进行包装
BufferedOutputStream bos = new BufferedOutputStream(fos);
int b;
while ( (b = bis.read()) != -1) {
bos.write(b);
}
//关闭输入流缓冲区
bis.close();
//关闭输出流缓存区
bos.close();
}
}
运行之后,刷新Eclipse项目,可以看到copy.war文件复制成功。注意上面,之后关闭的是输入流缓冲区对象和输出流缓冲区对象,而不是输入流和输出流对象,这点和前面有一点区别。原因也很简单,缓冲区对象本来就是包装了对应的输入流或者输出流,关闭了缓冲区,自然把包装里面对象也给一同关闭。
3.为什么要加入缓存思想
这里面涉及到一个装饰器和设计模式的概念,后面我们来学习。很明显,字节流一次读写一个数组的速度肯定要比一次读写一个字节的速度要快,效率高。缓冲区底层就是数组,这个我们在StringBuffer这个类也可以找到这种设计思想。
4.BufferedInputStream缓冲区具体原理
原理是BufferedInputStream底层用了一个数组,默认大小是8192个字节,也就是BufferedInputStream一次性会从文件读取8192个字节,然后返回给程序一个字节,程序在读取8192个字节之前不需要再次去访问和读取文件,直接从缓冲区读。直到缓冲区所有的都读取过,然后再去读取8192个字节,一直这样进行下去,直到任务结束。同样的BufferedOutputStream也是内置一个数组,默认大小也是8192字节。程序向流中写出字节时,不会直接写到文件,而是先写入到缓冲区,直到缓冲区写满,BufferedInputStream才会一次性把数据写入到文件中。