当前位置: 首页 > 编程日记 > 正文

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

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

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/54894451
本文出自【赵彦军的博客】

InputStream
|__FilterInputStream|__BufferedInputStream

首先抛出一个问题,有了InputStream为什么还要有BufferedInputStream?

BufferedInputStreamBufferedOutputStream这两个类分别是FilterInputStreamFilterOutputStream的子类,作为装饰器子类,使用它们可以防止每次读取/发送数据时进行实际的写操作,代表着使用缓冲区。

我们有必要知道不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!

同时正因为它们实现了缓冲功能,所以要注意在使用BufferedOutputStream写完数据后,要调用flush()方法或close()方法,强行将缓冲区中的数据写出。否则可能无法写出数据。与之相似还BufferedReaderBufferedWriter两个类。

现在就可以回答在本文的开头提出的问题:

BufferedInputStreamBufferedOutputStream类就是实现了缓冲功能的输入流/输出流。使用带缓冲的输入输出流,效率更高,速度更快。

总结:

  • BufferedInputStream 是缓冲输入流。它继承于FilterInputStream

  • BufferedInputStream 的作用是为另一个输入流添加一些功能,例如,提供“缓冲功能”以及支持mark()标记reset()重置方法

  • BufferedInputStream 本质上是通过一个内部缓冲区数组实现的。例如,在新建某输入流对应的BufferedInputStream后,当我们通过read()读取输入流的数据时,BufferedInputStream会将该输入流的数据分批的填入到缓冲区中。每当缓冲区中的数据被读完之后,输入流会再次填充数据缓冲区;如此反复,直到我们读完输入流数据位置。

BufferedInputStream API简介

源码关键字段分析


private static int defaultBufferSize = 8192;//内置缓存字节数组的大小 8KBprotected volatile byte buf[];  //内置缓存字节数组protected int count;    //当前buf中的字节总数、注意不是底层字节输入流的源中字节总数protected int pos;      //当前buf中下一个被读取的字节下标protected int markpos = -1; //最后一次调用mark(int readLimit)方法记录的buf中下一个被读取的字节的位置protected int marklimit;    //调用mark后、在后续调用reset()方法失败之前云寻的从in中读取的最大数据量、用于限制被标记后buffer的最大值

构造函数

BufferedInputStream(InputStream in) //使用默认buf大小、底层字节输入流构建bis BufferedInputStream(InputStream in, int size) //使用指定buf大小、底层字节输入流构建bis  

一般方法介绍

int available();  //返回底层流对应的源中有效可供读取的字节数      void close();  //关闭此流、释放与此流有关的所有资源  boolean markSupport();  //查看此流是否支持markvoid mark(int readLimit); //标记当前buf中读取下一个字节的下标  int read();  //读取buf中下一个字节  int read(byte[] b, int off, int len);  //读取buf中下一个字节  void reset();   //重置最后一次调用mark标记的buf中的位子  long skip(long n);  //跳过n个字节、 不仅仅是buf中的有效字节、也包括in的源中的字节 

BufferedOutputStream API简介

关键字段

protected byte[] buf;   //内置缓存字节数组、用于存放程序要写入out的字节  protected int count;   //内置缓存字节数组中现有字节总数 

构造函数

BufferedOutputStream(OutputStream out); //使用默认大小、底层字节输出流构造bos。默认缓冲大小是 8192 字节( 8KB )BufferedOutputStream(OutputStream out, int size);  //使用指定大小、底层字节输出流构造bos  

构造函数源码:

/*** Creates a new buffered output stream to write data to the* specified underlying output stream.* @param   out   the underlying output stream.*/public BufferedOutputStream(OutputStream out) {this(out, 8192);}/*** Creates a new buffered output stream to write data to the* specified underlying output stream with the specified buffer* size.** @param   out    the underlying output stream.* @param   size   the buffer size.* @exception IllegalArgumentException if size &lt;= 0.*/public BufferedOutputStream(OutputStream out, int size) {super(out);if (size <= 0) {throw new IllegalArgumentException("Buffer size <= 0");}buf = new byte[size];}

一般方法

//在这里提一句,`BufferedOutputStream`没有自己的`close`方法,当他调用父类`FilterOutputStrem`的方法关闭时,会间接调用自己实现的`flush`方法将buf中残存的字节flush到out中,再`out.flush()`到目的地中,DataOutputStream也是如此。 void  flush();  将写入bos中的数据flush到out指定的目的地中、注意这里不是flush到out中、因为其内部又调用了out.flush()  write(byte b);      将一个字节写入到buf中  write(byte[] b, int off, int len);      将b的一部分写入buf中 

那么什么时候flush()才有效呢?
答案是:当OutputStream是BufferedOutputStream时。

当写文件需要flush()的效果时,需要
FileOutputStream fos = new FileOutputStream("c:\a.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
也就是说,需要将FileOutputStream作为BufferedOutputStream构造函数的参数传入,然后对BufferedOutputStream进行写入操作,才能利用缓冲及flush()。

查看BufferedOutputStream的源代码,发现所谓的buffer其实就是一个byte[]。
BufferedOutputStream的每一次write其实是将内容写入byte[],当buffer容量到达上限时,会触发真正的磁盘写入。
而另一种触发磁盘写入的办法就是调用flush()了。

1.BufferedOutputStreamclose()时会自动flush
2.BufferedOutputStream在不调用close()的情况下,缓冲区不满,又需要把缓冲区的内容写入到文件或通过网络发送到别的机器时,才需要调用flush.

实战演练1:复制文件.
操作:使用缓存流将F盘根目录里面名字为:123.png 图片复制成 abc.png

package com.app;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;public class A3 {public static void main(String[] args) throws IOException {String filePath = "F:/123.png" ;String filePath2 = "F:/abc.png" ;File file = new File( filePath ) ;File file2 = new File( filePath2 ) ;copyFile( file , file2 );}/*** 复制文件* @param oldFile* @param newFile*/public static void copyFile( File oldFile , File newFile){InputStream inputStream = null ;BufferedInputStream bufferedInputStream = null ;OutputStream outputStream = null ;BufferedOutputStream bufferedOutputStream = null ;try {inputStream = new FileInputStream( oldFile ) ;bufferedInputStream = new BufferedInputStream( inputStream ) ;outputStream = new FileOutputStream( newFile ) ;bufferedOutputStream = new BufferedOutputStream( outputStream ) ;byte[] b=new byte[1024];   //代表一次最多读取1KB的内容int length = 0 ; //代表实际读取的字节数while( (length = bufferedInputStream.read( b ) )!= -1 ){//length 代表实际读取的字节数bufferedOutputStream.write(b, 0, length );}//缓冲区的内容写入到文件bufferedOutputStream.flush();} catch (FileNotFoundException e) {e.printStackTrace();}catch (IOException e) {e.printStackTrace();}finally {if( bufferedOutputStream != null ){try {bufferedOutputStream.close();} catch (IOException e) {e.printStackTrace();}}if( bufferedInputStream != null){try {bufferedInputStream.close();} catch (IOException e) {e.printStackTrace();}}if( inputStream != null ){try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}if ( outputStream != null ) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}}
}

效果图:

这里写图片描述

如何正确的关闭流

在上面的代码中,我们关闭流的代码是这样写的。

finally {if( bufferedOutputStream != null ){try {bufferedOutputStream.close();} catch (IOException e) {e.printStackTrace();}}if( bufferedInputStream != null){try {bufferedInputStream.close();} catch (IOException e) {e.printStackTrace();}}if( inputStream != null ){try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}if ( outputStream != null ) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}

思考:在处理流关闭完成后,我们还需要关闭节点流吗?

让我们带着问题去看源码:

  • bufferedOutputStream.close();
   /*** Closes this input stream and releases any system resources* associated with the stream.* Once the stream has been closed, further read(), available(), reset(),* or skip() invocations will throw an IOException.* Closing a previously closed stream has no effect.** @exception  IOException  if an I/O error occurs.*/public void close() throws IOException {byte[] buffer;while ( (buffer = buf) != null) {if (bufUpdater.compareAndSet(this, buffer, null)) {InputStream input = in;in = null;if (input != null)input.close();return;}// Else retry in case a new buf was CASed in fill()}}

close()方法的作用
1、关闭输入流,并且释放系统资源
2、BufferedInputStream装饰一个 InputStream 使之具有缓冲功能,is要关闭只需要调用最终被装饰出的对象的 close()方法即可,因为它最终会调用真正数据源对象的 close()方法。因此,可以只调用外层流的close方法关闭其装饰的内层流。

那么如果我们想逐个关闭流,我们该怎么做?

答案是:先关闭外层流,再关闭内层流。一般情况下是:先打开的后关闭,后打开的先关闭;另一种情况:看依赖关系,如果流a依赖流b,应该先关闭流a,再关闭流b。例如处理流a依赖节点流b,应该先关闭处理流a,再关闭节点流b

看懂了怎么正确的关闭流之后,那么我们就可以优化上面的代码了,只关闭外层的处理流。

finally {if( bufferedOutputStream != null ){try {bufferedOutputStream.close();} catch (IOException e) {e.printStackTrace();}}if( bufferedInputStream != null){try {bufferedInputStream.close();} catch (IOException e) {e.printStackTrace();}}}

个人微信号:zhaoyanjun125 , 欢迎关注

weixin200.jpg

转载于:https://www.cnblogs.com/zhaoyanjun/p/6376937.html

相关文章:

7-flutter Navigator 和Route

Route 和 Navigator 用于页面之间的跳转 一 Navigator 的 push 和 pop 用于页面之间的跳转 创建MaterialApp时可以指定routes参数&#xff0c;该参数是一个映射路由名称和构造器的Map 跳转的时候 使用 push 跳回的时候使用 pop import package:flutter/cupertino.dart; im…

小规模网络数据公开数据_大规模的在线公开课程曾经是100%免费的。 但是他们没有那样做。...

小规模网络数据公开数据I took one of the first Massive Open Online Courses (MOOCs) in 2011. Back then, everything was 100% free: the videos, the assignments, and the certificates. But in 2017, you can’t find this sort of free learning experience anymore.我…

swift -charts框架雷达图

参考资料 import UIKit import Chartsclass ViewController: UIViewController {let activities ["力量", "敏捷", "生命", "智力", "魔法"]override func viewDidLoad() {super.viewDidLoad()// Do any additional setup…

vector容器总结.xml

1 清空所有元素m_itemVector.clear(); 2 遍历vector<ITEM_CHECK>::iterator iterm_itemVector.begin(); for(i0;iter!m_itemVector.end();iter,i) { if(iter->flag-1) { break; } iter->flag1; } vector<ITEM_CHECK>::iterator iterm_itemVector.b…

Syncthing源码解析 - 第三方库

1&#xff0c;AudriusButkevicius/cli 网址&#xff1a;https://github.com/AudriusButkevicius/cli 2&#xff0c;bkaradzic/go-lz4 网址&#xff1a;https://github.com/bkaradzic/go-lz4 3&#xff0c;calmh 备注&#xff1a;这位是Syncthing项目创立者和最主要的开发者&…

安全工程师2017年真题_以下是2017年全球软件工程师的平均薪水

安全工程师2017年真题And here are those same salaries adjusted to San Francisco’s cost of living:以下是根据旧金山的生活费用调整后的相同工资&#xff1a; As you can see, cost of living is an important consideration. Also, you don’t need to move to San Fran…

测试思想 什么是软件测试(摘录)

什么是软件测试(摘录) by:授客 QQ&#xff1a;1033553122 IEEE 标准的定义:使用人工或自动的手段来运行或测定某个系统的过程&#xff0c;其目的在于检验;它是否满足规定的需求或是弄清预期结果与实际结果之间的差别。对软件测试还有一些不同的定义。 G.J.Myers给出的定义:“程…

8-flutter 异步和线程

线程和异步的UI 1 异步的使用 Dart 有一个单线程执行模型&#xff0c;支持Isolate&#xff08;一种在另外一种线程运行dart的方法&#xff09;,一个事件循环和异步编程。 可以使用async / await 来做网络请求不会挂起UI 使用http 导入 import ‘dart:io’; import ‘dart:c…

前端页面紫红色_谷歌正在开发一种神秘的新型移动操作系统,称为紫红色

前端页面紫红色Google seems to be building a replacement for Android called Fuchsia. Yesterday, they revealed what their new Armadillo user interface looks like (see photo above, courtesy of Ars Technica).谷歌似乎正在建立一个名为Fuchsia的 Android替代产品。 …

iOS UIButton 文字图片上下左右布局

例如文字在左 图片在右,iOS 9 之后一句话搞定 backBtn.semanticContentAttribute UISemanticContentAttributeForceRightToLeft;按钮标题居左实现 dateBtn.contentHorizontalAlignment UIControlContentHorizontalAlignmentLeft; dateBtn.contentEdgeInsets UIEdgeInsetsMak…

linux xampp eclipse xdebug 无法进入断点

一、xampp 版本 1.8.3-5 xampp安装后会自动集成xdebug,目录一般为 /opt/lampp/lib/php/extensions/***-debug-***目录 关于php 与php.ini路径 php程序路径为&#xff1a;/opt/lampp/bin/ php.ini配置文件路径为&#xff1a;/opt/lampp/etc/ 1、配置文件一般在/opt/lampp/etc/ph…

sliva数据库简介--转载

sliva rRNA数据库&#xff08;http://www.arb-silva.de/&#xff09;用来检查和比对RNA序列&#xff0c;既可以针对16S/18S,SSU&#xff0c;也可以针对23S/28S, LSU&#xff0c;包括了Bacteria, Archaea and Eukarya。同时也是ARB的官方指定数据库。 LSU: Large subunit (23S/2…

haproxy ssl_我们如何微调HAProxy以实现2,000,000个并发SSL连接

haproxy sslby Sachin Malhotra由Sachin Malhotra 我们如何微调HAProxy以实现2,000,000个并发SSL连接 (How we fine-tuned HAProxy to achieve 2,000,000 concurrent SSL connections) If you look at the above screenshot closely, you’ll find two important pieces of in…

OC文件操作(1)

1.文件的浅度遍历与深度遍历&#xff1a; //NSFileManager * fm [[NSFileManager alloc]init];//创建文件管理器 //第一步创建一个文件管理器 NSError * error nil; //显示路径下的内容,作用类似于ls -a指令 //返回值是把目录下的内容放到NSArray中 //浅度遍历 NSFileManager …

10-flutter 使用http包请求和网络指示器

使用http package 进行网络请求操作 1 安装步骤 Step1 在pubspec.yaml 文件中添加依赖 dependencies:http: ^0.12.01Step2 flutter packages getStep3 导入头文件 import ‘package:http/http.dart’ as http; 2 使用 var responseBody;http.Response response await http.…

使用nat方式解决虚拟机联网问题

本文全文参考&#xff1a;http://jingyan.baidu.com/album/4e5b3e1957979d91901e24f1.html?picindex1&#xff0c;谢谢 对于很多的linux初学者来说&#xff0c;最开始学习linux时通常是在虚拟机上进行的&#xff0c;然而对于新手来说虚拟机联网会对他们来说是比较困难的。…

老年痴呆 数字化_设计老年人愉快数字体验的5条原则

老年痴呆 数字化by Kaye Mao毛凯(Kaye Mao) 设计老年人愉快数字体验的5条原则 (5 Principles for Designing Delightful Digital Experiences for Seniors) When we got my grandfather his first smart phone, he was thrilled. He had heard all about the wonders of video…

hdu 3664 1~n排列(aii ) 为k个数

http://acm.hdu.edu.cn/showproblem.php?pid3664 求1~n的排列个数&#xff0c;使得逆序数&#xff08;ai>i ) 为给定的k. dp[i][j]表示前1~i的排列中&#xff0c;有j个数是逆序数的个数. #include <cstdio> #include <cstdlib> #include <cmath> #includ…

四边参数值的设定

border&#xff0c;margin&#xff0c;padding 拿border举例 border&#xff1a;上&#xff0c;右&#xff0c;下&#xff0c;左。 border&#xff1a;上下&#xff0c;左右。 border&#xff1a;上下左右。 border&#xff1a;上&#xff0c;左右&#xff0c;下。转载于:https…

11-flutter事件监听

事件监听 1 本身支持事件检测&#xff0c;就可以直接使用onpress body:Center(child: RaisedButton(child: Text("Click"),onPressed: (){print("我被Click了");}),),2 如果本身不支持事件的检测&#xff0c; 使用 GestureDetector 添加一个点击事件 hom…

react前端开发_是的,React正在接管前端开发。 问题是为什么。

react前端开发by Samer Buna通过Samer Buna 是的&#xff0c;React正在接管前端开发。 问题是为什么。 (Yes, React is taking over front-end development. The question is why.) Update: This article is now part of my book “React.js Beyond The Basics”.更新&#xf…

12-flutter Textfield的使用

获取用户的输入用 TextField 或者TextFormField 的实现&#xff0c;通过控制器来实现获取用户的输入。 1 TextField 的属性 const TextField({Key key,this.controller,this.focusNode,// 这个属性可以用来监听输入框是否获取this.decoration const InputDecoration(),Text…

MyEclipse10整合Axis2插件

1、下载axis2的eclipse插件 2、把下载好的两个插件包解压后放置myeclipse10安装目录下的dropins文件夹中 3、重启MyEclipse10后 File->New->Other 到此Axis2插件安装完毕。 转载于:https://www.cnblogs.com/dreammyle/p/4036224.html

STM32GPIO管脚设置

&#xff08;1&#xff09;GPIO_Mode_AIN 模拟输入 &#xff08;2&#xff09;GPIO_Mode_IN_FLOATING 浮空输入&#xff08;3&#xff09;GPIO_Mode_IPD 下拉输入 &#xff08;4&#xff09;GPIO_Mode_IPU 上拉输入 &#xff08;5&#xff09;GPIO_Mode_Out_OD 开漏输出&#x…

数据结构中等号表示什么_通过分析2016年最重要的252个中等故事我学到了什么...

数据结构中等号表示什么Medium may be struggling to find a sustainable business model, but they have years worth of funding left, and more readers than ever.中型企业可能很难找到一种可持续的商业模式&#xff0c;但他们还有数年的可用资金&#xff0c;而且读者比以往…

event事件

10.2.6 事件传播 当事件目标是Window对象或其他一些单独对象&#xff08;比如XMLHttpRequest&#xff09;时&#xff0c;浏览器会简单的通过调用对象上适当的处理程序响应事件。 在调用在目标元素上注册的事件处理函数后&#xff0c;大部分事件会“冒泡”到DOM树根。 发生在文档…

[原创]用命令行工具删除TFS2010服务器上的工作区信息

下面的示例显示有关所有计算机上的所有用户已在地址 http://myserver:8080/tfs/DefaultCollection 上的以下团队项目集合中创建的所有工作区的列表。 c:\projects>tf workspaces /owner:*/computer:* /collection:http://myserver:8080/tfs/DefaultCollection tf workspace …

13-flutter 加载图片

Image Widget 1 flutter 加载图片的方式 new Image从ImageProvider 中获取图像new Image.asset使用key 从assetBundle 获取图片Image.network从网络中获取图片Image.file从本地文件获取图片Image.memory用来加载Uint8List资源&#xff08;字节数组&#xff09;图片 2 image 支…

react 组件样式_如何使用样式化组件为React组件创建视觉变体

react 组件样式by Gilad Dayagi通过吉拉德达亚吉 如何使用样式化组件为React组件创建视觉变体 (How to create visual variants for React components using styled-components) Styled-components is a library for styling React components that took the React world by s…

HDU 1406 完数

完数 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 18647 Accepted Submission(s): 6894 Problem Description完数的定义&#xff1a;如果一个大于1的正整数的所有因子之和等于它的本身&#xff0c;则称这个…