J05-Java IO流总结五 《 BufferedInputStream和BufferedOutputStream 》
1. 概念简介
BufferedInputStream和BufferedOutputStream是带缓冲区的字节输入输出处理流。它们本身并不具有IO流的读取与写入功能,只是在别的流(节点流或其他处理流)上加上缓冲功能以提高效率,就像是把别的流包装起来一样,因此缓冲流是一种处理流。事实上,这两个处理流(BufferedInputStream和 BufferedOutputStream),加上BufferedReader和BufferedWriter,这四个流在设计时使用到的正是装饰设计模式,通过装饰设计模式,得以在其他的流的基础上增加缓冲的功能。
当对文件或者其他数据源进行频繁的读写操作时,效率比较低,这时如果使用缓冲流就能够更高效的读写信息。因为缓冲流是先将数据缓存起来,然后当缓存区存满后或者手动刷新时再一次性的读取到程序或写入目的地。
2. 使用FileInputStream和FileOutputStream复制文件的原理图

3. 使用BufferedInputStream和BufferedOutputStream复制文件的原理图

3.1 MyBos
由源码可知,BufferedOutputStream自身并没有实现将数据写入目的地的功能,真正的写入功能其实还是由它所装饰的字节输出流os来实现的。通过缓冲区的缓冲作用,增加了内存与内存之间的交互,减少了内存与磁盘的直接交互,以此提升I/O的效率。
下面是在参考了BufferedOutputStream的源码之后,自己实现的缓冲字节输出流,原理如下:首先在MyBos内部包装了一个真正具有将数据输出到目的地功能的字节输出流os;还定义了一个字节缓冲数组buf,默认大小为8K,当调用write(byte b)或write(byte[] buf, int off, int len)方法将数据写出时,并不是直接将数据写出到目的地,首选是先将数据写到MyBos中自定义的缓冲区buf中,只有当缓冲区满了或者手动刷新的时候,才会将缓冲区的数据一次性写入到目的地。
自己实现的缓冲字节输出流的代码如下所示:
import java.io.IOException;
import java.io.OutputStream; public class MyBos { private byte[] buf; //缓冲字节数组
private int count; //记录目前缓冲数组中的有效字节数
private OutputStream os;//被装饰的底层输出字节流 //构造方法
public MyBos(OutputStream os) throws Exception {
this(os, 8192); //若不显式指定缓冲数组的大小,则默认分配8k空间
} public MyBos(OutputStream os, int size) throws Exception {
if(size < 0) {
throw new Exception("缓冲区空间大小分配错误:" + size);
}
this.os = os;
buf = new byte[size];
} /**
* 写出单个字节数据
* @param b 写出的字节数据
* @throws IOException
*/
public void write(int b) throws IOException {
if(count == buf.length) {//若count == buf.length,说明缓冲区buf已满,则先将缓冲区数据写出
os.write(buf); //调用os的wirte(byte[] buf)方法讲数据写出!
count = 0; //重置count
} buf[count++] = (byte)b; //将字节数据写入缓冲区,写入到count所在索引位置上
} /**
* 将字节数组b[offset, offset+len)部分写出
* @param b 字节数组
* @param offset 开始位置
* @param len 长度
* @throws Exception
*/
public void write(byte[] b, int offset, int len) throws Exception { if(offset < 0 || len < 0 || b.length < (offset + len)) {
throw new Exception("数组索引越界异常!");
} if(len > buf.length) { //若写出的字节数组b数据大于缓冲数组
flush(); //则先调用flush()方法将缓冲数组的数据写出
os.write(b, offset, len); //直接将数组b的数据通过os的wirte方法写出,不写入缓冲数组了
return;
} if(len > buf.length - count) { //若缓冲数组剩余空间不足len长度
flush(); //则先将缓冲数组的数据写出
} System.arraycopy(b, offset, buf, count, len);
count += len; } /**
* 刷新缓冲区
* @throws IOException
*/
public void flush() throws IOException {
if(count > 0) { //若缓冲区中有数据,则调用底层输出流os将数据写出
os.write(buf, 0, count);
os.flush();
count = 0; //重置count
}
} /**
* 关闭流
* @throws IOException
*/
public void close() throws IOException {
if(null != os) {
flush(); //先将缓冲数组的数据写出
os.close(); //接着关闭底层数据流os
}
}
}
3.2 MyBis
由BufferedInputStream的源码可知,该类的内部同样有一个字节缓冲区buf,每次读取数据时,它会先检查缓冲区中是否有数据,若有则直接从缓冲区中取数,若是没有,则先通过底层输入流将指定大小(默认是8192个字节)的数据从底层读取到缓冲区中,再从缓冲区拿数。
跟BufferedOutputStream一样,BufferedInputStream自身也没有实现将数据从源文件读入内存的功能,真正的读取功能其实还是由它所装饰的底层字节输入流is来实现的。通过缓冲区的缓冲作用,增加了内存与内存之间的交互,减少了内存与磁盘的直接交互,以此提升I/O的效率。
自己实现的BufferedInputStream示例代码:
import java.io.IOException;
import java.io.InputStream; public class MyBis {
//用于访问底层数据的底层流
private InputStream is;
//字节数组缓冲区
byte[] buf;
//默认缓存大小8k
public static final int DEFAULT_BUF_SIZE = 8192;
//记录缓冲区中 待读取的字节数
private int count;
//用于记录读取到当前 buf 中字节数据的位置
private int pos; //构造方法
public MyBis(InputStream is) throws Exception {
this(is, DEFAULT_BUF_SIZE);
} public MyBis(InputStream is, int size) throws Exception {
if(size < 0) {
throw new Exception("\"缓冲区空间大小分配错误:\" + size");
}
this.is = is;
buf = new byte[DEFAULT_BUF_SIZE];
} /**
* 从缓冲区中读取下一个字节的数据,如果数据到到了末尾,返回 -1
* @return 读取到的字节数据的 int 形式,如果读取到了流的末尾,返回 -1
* @throws IOException
*/
public int read() throws IOException {
if(pos == count) {//若读取的下一个字节数已经到达有效数据的末尾
count = is.read(buf);//则通过底层的输入流,一次性读取 8192 个字节数据到缓冲区中来。
if(-1 == count) {//若is 没有读取到数据,直接返回-1
return -1;
}
//若is读取到数据了,将pos设置为第一个字节
pos = 0;
} //返回读取到的字节数据的 int 形式
return buf[pos++] & 0xff;
} /**
* 处理流的关闭问题:只关闭处理流即可,处理流的关闭会将底层的流关闭掉。
* @throws IOException
*/
public void close() throws IOException {
if(null != is) {
is.close();
}
}
}
测试自己写的字节缓冲输入流:
import java.io.FileInputStream;
import java.io.IOException; public class TestMyBis {
public static void main(String[] args) {
MyBis mb = null; try {
mb = new MyBis(new FileInputStream("./src/res/1.txt")); int value = 0; while(-1 != (value = mb.read())) {
System.out.print((char)value);
} } catch (Exception e) {
e.printStackTrace();
} finally {
if(null != mb) {
try {
mb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
代码运行效果:

4. 字节缓冲流应用示例
示例代码:
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 BufferedStreamTest {
public static void main(String[] args) {
BufferedInputStream bis = null;
BufferedOutputStream bos = null; try {
//使用缓冲流
bis = new BufferedInputStream(new FileInputStream("e:/test_file/data_structure.avi"));
bos = new BufferedOutputStream(new FileOutputStream("e:/test_file/data_structure_copy.avi"));
int len = 0;
byte[] buf = new byte[1024*1024];//因为读取的源文件较大,所以这里分配的空间大一点 while(-1 != (len = bis.read(buf))) {
bos.write(buf, 0, len);
} } catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(null != bos) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(null != bis) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} }
}
最后,由BufferedInputStream和BufferedOutputStream这两个类的源码或API可以看出,它们没有新增任何新的方法,使用的都是常见的read()、read(byte[] b)、write(int b)、write(byte[] buf, int off, int len)等方法。
J05-Java IO流总结五 《 BufferedInputStream和BufferedOutputStream 》的更多相关文章
- Java IO(十) BufferedInputStream 和 BufferedOutputStream
Java IO(十)BufferedInputStream 和 BufferedOutputStream 一.BufferedInputStream 和 BufferedOutputStream (一 ...
- java IO流 (五) 转换流的使用 以及编码集
转换流的使用 1.转换流涉及到的类:属于字符流InputStreamReader:将一个字节的输入流转换为字符的输入流解码:字节.字节数组 --->字符数组.字符串 OutputStreamWr ...
- Java IO流学习总结三:缓冲流-BufferedInputStream、BufferedOutputStream
Java IO流学习总结三:缓冲流-BufferedInputStream.BufferedOutputStream 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/ ...
- Java IO流详解(五)——缓冲流
缓冲流也叫高效流,是处理流的一种,即是作用在流上的流.其目的就是加快读取和写入数据的速度. 缓冲流本身并没有IO功能,只是在别的流上加上缓冲效果从而提高了效率.当对文件或其他目标频繁读写或操作效率低, ...
- Java IO流 BufferedInputStream、BufferedOutputStream的基本使用
BufferedInputStream.BufferedOutputStream的基本使用 BufferedInputStream是FilterInputStream流的子类,FilterInputS ...
- Java IO流题库
一. 填空题 Java IO流可以分为 节点流 和处理流两大类,其中前者处于IO操作的第一线,所有操作必须通过他们进行. 输入流的唯一目的是提供通往数据的通道,程序可以通过这个通道读取数 ...
- Java IO流01-总叙
Java IO包体系结构图: 1.流式部分――IO的主体部分: 2.非流式部分——主要包含一些辅助流式部分的类,如:File类.RandomAccessFile类和FileDescriptor等类: ...
- Java IO流学习
Java IO流学习 Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是 ...
- Java IO流详解(一)——简单介绍
文件在程序中是以流的形式来传输的.所以用Java来传输文件就得使用到Java IO流. 1.流的概念和作用 流:代表任何有能力产出数据的数据源对象或者是有能力接受数据的接收端对象<Thinkin ...
- Java:IO流与文件基础
Java:IO流与文件基础 说明: 本章内容将会持续更新,大家可以关注一下并给我提供建议,谢谢啦. 走进流 什么是流 流:从源到目的地的字节的有序序列. 在Java中,可以从其中读取一个字节序列的对象 ...
随机推荐
- 使用delphi 开发多层应用(二十三)KbmMW 的WIB
解释WIB 是什么之前,先回顾以下我们前面的各种服务工作方式.前面的各种服务的工作方式都是请求/应答方式. 客户端发送请求,服务器端根据客户端的请求,返回相应的结果.这种方式是一种顺序式访问,是一种紧 ...
- Web Service测试工具小汇
1..NET WebService Studio 这款工具出自微软内部,最大的优点是可视化很好,不用去看那些XML文件,WebService的基础内容就有XML,但是测试中Case过多,每次测试结果都 ...
- IntelliJ IDEA 2017版 spring-boot使用JdbcTemplate实例
搭建总框架: (1)在pom.xml加入jdbcTemplate的依赖: (2)编写Dao类,声明为:@Repository,引入JdbcTemplate (3)编写Service类,引入Dao进行使 ...
- UVa 11292 Dragon of Loowater (水题,排序)
题意:有n个条龙,在雇佣勇士去杀,每个勇士能力值为x,只能杀死头的直径y小于或等于自己能力值的龙,只能被雇佣一次,并且你要给x赏金,求最少的赏金. 析:很简单么,很明显,能力值高的杀直径大的,低的杀直 ...
- c# Clipboard.SetDataObject(bmp1) 在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。 只有将调试器附加到该进程才会引发此异常
c# Clipboard.SetDataObject(bmp1) 在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式.请确保您的 Main 函数带有 STAThreadAttri ...
- python logging 实现的进程安全的文件回滚日志类
python标准库中的logging模块在记录日志时经常会用到,但在实际使用发现它自带的用于本地日志回滚的类 logging.handlers.RotatingFileHandler 在多进程环境下会 ...
- (并查集)Travel -- hdu -- 5441(2015 ACM/ICPC Asia Regional Changchun Online )
http://acm.hdu.edu.cn/showproblem.php?pid=5441 Travel Time Limit: 1500/1000 MS (Java/Others) Memo ...
- 20155302 2016-2017-2 《Java程序设计》第六周学习总结
20155302 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 Java中的流分为两种,一种是字节流,另一种是字符流,分别由四个抽象类来表示(每种流包括输入 ...
- 对SpringDAO层支持的总结
1.问题 1.JDBC/ORM框架(如Hibernate)开发中编程模型有哪些缺点? 如JDBC 2.解决方案(模板设计模式,本质:将可变的和不可变的分离) 模板方法模式:定义操作的步骤(固定的 ...
- [Zend Mail]发送中文名附件出现乱码解决方案
Zend Framework 1.0.* “=?UTF-8?B?”.base64_encode($title).“?=” 发送中文名附件,结果如图: 英文名附件,结果截图: 解决办法就是将中文文件名拼 ...