先介绍一下为啥比较他俩,因为BufferedInputStream是FileInputStream 的装饰者,但是我发现FileInputStream 中也是有缓存的,所以我就好奇装饰者起什么作用呢,这就是我写这篇文章的原因。

先说结论,当缓冲区的大小比8192小的时候,BufferedInputStream的效率更好。

发现是BufferedInputStream有一个默认为8192字节的缓冲区,当自定义的缓冲区小于8192的时候,默认一次性从硬盘中读取8192字节到内存中,然后每次只按自定义的缓冲量返回数据,性能好在了减少了读取硬盘的次数。

BufferedInputStream的示意图

FileInputStream 示意图

示例

public class FileOperator {/** buffer size in bytes */final static int BUFFER_SIZE = 100;/*** copy file using FileInputStream & FileOutputStream* @param src copy from* @param dest copy to* @return;*/public static void copyWithFileStream(File src, File dest){FileInputStream input = null;FileOutputStream output = null;try {input = new FileInputStream(src);output = new FileOutputStream(dest);byte[] buffer = new byte[BUFFER_SIZE];int copySize;while ((copySize = input.read(buffer)) > 0){output.write(buffer, 0, copySize);output.flush();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {input.close();output.close();} catch (IOException e) {e.printStackTrace();}}}/*** copy file using BufferedInputStream & BufferedOutputStream* @param src copy from file* @param dest copy to file* @return;*/public static void copyWithBufferedStream(File src, File dest){BufferedInputStream bufferedInput = null;BufferedOutputStream bufferedOutput = null;try {bufferedInput = new BufferedInputStream(new FileInputStream(src));bufferedOutput = new BufferedOutputStream(new FileOutputStream(dest));byte[] buffer = new byte[BUFFER_SIZE];int copySize;while ((copySize = bufferedInput.read(buffer)) > 0){bufferedOutput.write(buffer, 0, copySize);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {bufferedInput.close();bufferedOutput.close();} catch (IOException e) {e.printStackTrace();}}}
}class FileOperatorTest{public static void main(String args[]){File src = new File("test.txt");File dest = new File("copyTest.txt");try {if (!dest.exists()){dest.createNewFile();}} catch (IOException e) {e.printStackTrace();}//test copy using FileStreamint startTime = System.currentTimeMillis();FileOperator.copyWithFileStream(src, dest);int endTime = System.currentTimeMillis();System.out.println("Copy file using FileStream takes : " + (endTime - startTime) + " ms.");//test copy using BufferedStreamstartTime = System.currentTimeMillis();FileOperator.copyWithBufferedStream(src, dest);endTime = System.currentTimeMillis();System.out.println("Copy file using BufferedStream takes : " + (endTime - startTime) + " ms.");}
}

【运行结果】
测试文件大小约为900M,以下是在设定BUFFER_SIZE为不同值时的一次执行结果:

BUFFER_SIZE = 100
Copy file using FileStream takes: 42680 ms.
Copy file using BufferedStream takes: 2407 ms.

BUFFER_SIZE = 8192
Copy file using FileStream takes: 1689 ms.
Copy file using BufferedStream takes: 1654 ms.

BUFFER_SIZE = 1000000
Copy file using FileStream takes: 957 ms.
Copy file using BufferedStream takes: 929 ms.

关键源码分析如下

BufferedInputStream的源码

public synchronized int read(byte b[], int off, int len)throws IOException{getBufIfOpen(); // Check for closed streamif ((off | len | (off + len) | (b.length - (off + len))) < 0) {throw new IndexOutOfBoundsException();} else if (len == 0) {return 0;}int n = 0;for (;;) {int nread = read1(b, off + n, len - n);if (nread <= 0)return (n == 0) ? nread : n;n += nread;if (n >= len)return n;// if not closed but no bytes available, returnInputStream input = in;if (input != null && input.available() <= 0)return n;}}

getBufIfOpen方法中的buf是8192,所以buffer =8192。其中类实例化的时候,buf为默认长度

private byte[] getBufIfOpen() throws IOException {byte[] buffer = buf;if (buffer == null)throw new IOException("Stream closed");return buffer;}
//构造函数设置默认长度
public BufferedInputStream(InputStream in) {this(in, DEFAULT_BUFFER_SIZE);}

默认长度

private static int DEFAULT_BUFFER_SIZE = 8192;

read1方法是重点

 private int read1(byte[] b, int off, int len) throws IOException {int avail = count - pos;if (avail <= 0) {/* If the requested length is at least as large as the buffer, andif there is no mark/reset activity, do not bother to copy thebytes into the local buffer.  In this way buffered streams willcascade harmlessly. */if (len >= getBufIfOpen().length && markpos < 0) {return getInIfOpen().read(b, off, len);}fill();avail = count - pos;if (avail <= 0) return -1;}int cnt = (avail < len) ? avail : len;System.arraycopy(getBufIfOpen(), pos, b, off, cnt);pos += cnt;return cnt;}

count=0,pos=0 所以avail =0

当自定义的长度为100时,所以len=100 len >= getBufIfOpen().length(8192)的条件是不满足的,所以不进入结构体,接下来调用fill方法

private void fill() throws IOException {byte[] buffer = getBufIfOpen();if (markpos < 0)pos = 0;            /* no mark: throw away the buffer */else if (pos >= buffer.length)  /* no room left in buffer */if (markpos > 0) {  /* can throw away early part of the buffer */int sz = pos - markpos;System.arraycopy(buffer, markpos, buffer, 0, sz);pos = sz;markpos = 0;} else if (buffer.length >= marklimit) {markpos = -1;   /* buffer got too big, invalidate mark */pos = 0;        /* drop buffer contents */} else if (buffer.length >= MAX_BUFFER_SIZE) {throw new OutOfMemoryError("Required array size too large");} else {            /* grow buffer */int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?pos * 2 : MAX_BUFFER_SIZE;if (nsz > marklimit)nsz = marklimit;byte nbuf[] = new byte[nsz];System.arraycopy(buffer, 0, nbuf, 0, pos);if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {// Can't replace buf if there was an async close.// Note: This would need to be changed if fill()// is ever made accessible to multiple threads.// But for now, the only way CAS can fail is via close.// assert buf == null;throw new IOException("Stream closed");}buffer = nbuf;}count = pos;int n = getInIfOpen().read(buffer, pos, buffer.length - pos);if (n > 0)count = n + pos;}

其中markpos =-1,所以pos=0

pos >= buffer.length的条件是不满足的,所以执行到count=pos=0

int n = getInIfOpen().read(buffer, pos, buffer.length - pos);

private InputStream getInIfOpen() throws IOException {InputStream input = in;if (input == null)throw new IOException("Stream closed");return input;}

这个就是调用了inputsteram的read方法,就是按缓存量为8192的进行读取的

buffer有了数据,由于是同一个引用,所以buf缓存中也有了数据

n=8192,count=8192

回到read1方法 avail = count - pos;

avail=8192,接下来的三元运算 cnt=100

System.arraycopy(getBufIfOpen(), pos, b, off, cnt);

public static native void arraycopy(Object src,  int  srcPos,Object dest, int destPos,int length);

其中的getBufIfOpen()就是取buf字节数组,就是有了数据的8192的字节数组,就是将buf的前100个字节复制到b中就是自定义的字节数组中

然后pos按len长度自增,返回cnt=100

返回到read方法就不解释了,挺简单了

上面例子搬运自下面的大佬

FileInputStream 与 BufferedInputStream 效率对比 - 戴仓薯 - 博客园

FileInputStream 与 BufferedInputStream的比较相关推荐

  1. FileInputStream与BufferedInputStream有哪些区别?

    文章目录 前言 一.FileInputStream(文件输入流) 1.逐个字节读取: 2.批量字节读取: 二.BufferedInputStream(缓冲输入流) 前言 InputStream(字节输 ...

  2. Java API —— IO流( FileInputStream FileOutputStream BufferedInputStream BufferedOutputStream )...

    1.IO流概述 · IO流用来处理设备之间的数据传输        · 上传文件和下载文件        · Java对数据的操作是通过流的方式 · Java用于操作流的对象都在IO包中 2.IO流分 ...

  3. FileInputStream和BufferedInputStream的比较

    InputStream是Java标准库提供的最基本的输入流,位于java.io包里,InputStream是一个抽象类,是所有输入流的超类 FileInputStream是InputStream的子类 ...

  4. FileInputStream与BufferedInputStream的区别

    FileInputStream是InputStream的子类,即从文件流中读取数据,它的父类InputStream是java中自带的输入流,位于java.io包下,是一个抽象类,实现Closeable ...

  5. Java IO流学习总结三:缓冲流-BufferedInputStream、BufferedOutputStream

    Java IO流学习总结三:缓冲流-BufferedInputStream.BufferedOutputStream 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/ ...

  6. BufferedInputStream与ImageInputStream

    转载自 BufferedInputStream与ImageInputStream BufferedInputStream读取图片文件(jpg格式),但是图片大小在1M到200M之间都有,由于图片太大, ...

  7. BufferedInputStream。。。。。。。BufferedReader和BufferedWriter

    BufferedInputStream是套在某个其他的InputStream外,起着缓存的功能,用来改善里面那个InputStream的性能(如果可能的话),它自己不能脱离里面那个单独存在.FileI ...

  8. FileReader FileInputStream InputStreamReader BufferedReader 作用与区别

    FileReader FileInputStream InputStreamReader BufferedReader 作用与区别 ava.io下面有两个抽象类:InputStream和Reader ...

  9. java缓冲输入流_java入门 -- Java I/O(五)输入缓冲流BufferedInputStream

    /* * 缓冲输入字节流: * 作用:提高输入效率,比缓冲字节流跟高 * 输入字节流体系: * ----| InputStream 抽象列 * ---------| FileInputStream 读 ...

最新文章

  1. Java-Web机试练习题一、后台管理系统——管理员管理模块
  2. cell操作-matlab
  3. 给将要进入职场的同学 - 开发软件不是闭卷考试
  4. Axure通用web端元件库rplib文件格式+移动端app通用元件库rplib文件格式+电脑端动态可视化图表元件库+数据展示+操作反馈+通用模板+数据录入+列表页+表单页+详情页+通用版布局
  5. Atitit ACID解决方案2PC(两阶段提交)  跨越多个数据库实例的ACID保证
  6. Redis(1)——NoSQL数据库简介
  7. MacOS Ventura 13.0 Beta3 (22A5295i) 带 OC 0.8.2 三分区原版黑苹果镜像
  8. 护眼html颜色,在电脑中设置护眼颜色、更换网页背景色、一键护眼
  9. 级联样式单与CSS选择器
  10. Sonar代码规则之TOP30详解
  11. python对时间序列的DataFrame数据按时间段进行切分求和
  12. 互联网DSP广告系统架构及关键技术解析 | 广告行业资深架构师亲述
  13. 容器安全:深度防御策略
  14. 【小程序】开发需要注意的地方(一)
  15. UcosII移植、调度、功能、运行流程解析
  16. 1号店详情页(共5页)
  17. mac环境下搭建hexo+github pages+next个人博客
  18. 办公技巧:如何修改PDF文件的日期格式
  19. 把Excel批注的“红三角”放在单元格左上角_干货!《跟王佩丰学Excel教程》笔记...
  20. 深富策略短线消化市场情绪

热门文章

  1. 海量数据去重之SimHash算法简介和应用
  2. wx网罗系列之翔实:使用C++开发wxWidgets程序
  3. 英语中的非谓语动词小结
  4. 对比学习顶会论文系列-3-2
  5. STM32 DAC 输出正弦波、三角波、方波
  6. 详解注意力机制和Transformer
  7. 简单工厂模式的实现及优缺点
  8. 内存的分配与回收实验
  9. 数据库CREATE TRIGGER 触发器
  10. 博士在读,在家无法科研的你,在忙些什么?