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 》的更多相关文章

  1. Java IO(十) BufferedInputStream 和 BufferedOutputStream

    Java IO(十)BufferedInputStream 和 BufferedOutputStream 一.BufferedInputStream 和 BufferedOutputStream (一 ...

  2. java IO流 (五) 转换流的使用 以及编码集

    转换流的使用 1.转换流涉及到的类:属于字符流InputStreamReader:将一个字节的输入流转换为字符的输入流解码:字节.字节数组 --->字符数组.字符串 OutputStreamWr ...

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

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

  4. Java IO流详解(五)——缓冲流

    缓冲流也叫高效流,是处理流的一种,即是作用在流上的流.其目的就是加快读取和写入数据的速度. 缓冲流本身并没有IO功能,只是在别的流上加上缓冲效果从而提高了效率.当对文件或其他目标频繁读写或操作效率低, ...

  5. Java IO流 BufferedInputStream、BufferedOutputStream的基本使用

    BufferedInputStream.BufferedOutputStream的基本使用 BufferedInputStream是FilterInputStream流的子类,FilterInputS ...

  6. Java IO流题库

    一.    填空题 Java IO流可以分为   节点流   和处理流两大类,其中前者处于IO操作的第一线,所有操作必须通过他们进行. 输入流的唯一目的是提供通往数据的通道,程序可以通过这个通道读取数 ...

  7. Java IO流01-总叙

     Java IO包体系结构图: 1.流式部分――IO的主体部分: 2.非流式部分——主要包含一些辅助流式部分的类,如:File类.RandomAccessFile类和FileDescriptor等类: ...

  8. Java IO流学习

    Java IO流学习 Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是 ...

  9. Java IO流详解(一)——简单介绍

    文件在程序中是以流的形式来传输的.所以用Java来传输文件就得使用到Java IO流. 1.流的概念和作用 流:代表任何有能力产出数据的数据源对象或者是有能力接受数据的接收端对象<Thinkin ...

  10. Java:IO流与文件基础

    Java:IO流与文件基础 说明: 本章内容将会持续更新,大家可以关注一下并给我提供建议,谢谢啦. 走进流 什么是流 流:从源到目的地的字节的有序序列. 在Java中,可以从其中读取一个字节序列的对象 ...

随机推荐

  1. 2018.10.13 bzo1934: [Shoi2007]Vote 善意的投票(最小割)

    传送门 最小割定义题. 按照题意建边就行了. 考虑把冲突变成把aaa选入不与自己匹配的集合所需要付出的代价. 然后跑最小割就行了. 代码: #include<bits/stdc++.h> ...

  2. 2018.07.06 POJ2536 Gopher II(二分图匹配)

    Gopher II Time Limit: 2000MS Memory Limit: 65536K Description The gopher family, having averted the ...

  3. 初探Java反射机制

    反射库提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵java代码的程序库.这项功能被大量地应用于JavaBeans中.反射机制提供了在运行状态中获得和调用修改任何一个类的属性和方法的能力. ...

  4. IP之ALTDDIO_in仿真

    需要添加altera_mf库,才可以仿真. 上升沿输出,把前一个时钟的数据输出来. `timescale 1 ns/ 1 ns; module altddio_in_ip_tb; reg rst; r ...

  5. PAT甲 1048. Find Coins (25) 2016-09-09 23:15 29人阅读 评论(0) 收藏

    1048. Find Coins (25) 时间限制 50 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Eva loves t ...

  6. springmvc 开涛 数据验证

    两种方式:编程和声明. 编程需要:验证器,控制器,servlet.xml,错误码设置 声明需要:加jar包,控制器,跟孔浩讲得类似 错误消息设置的两种方式:硬编码:从资源文件中读取(默认,自定义).

  7. Android-Java卖票案例-推荐此方式Runnable

    上一篇博客 Android-卖票案例static-不推荐此方式,讲解了卖票案例是 private static int ticket = 10;,static静态的这种方式来解决卖票多卖30张的问题, ...

  8. 将Heap RID转换成RID格式

    使用DBCC PAGE命令查看索引叶子层中的索引键(最后一个参数为3才会显示索引键对应的HEAP RID)时,可以使用下面的SQL将HEAP RID转换成 FileId:PageId:SlotNo的格 ...

  9. clob 转 String

    import javax.sql.rowset.serial.SerialClob; import java.io.BufferedReader; import java.io.IOException ...

  10. char、varchar、nchar、nvarchar特点比较

    于程序中的string型字段,SQLServer中有char.varchar.nchar.nvarchar四种类型来对应(暂时不考虑text和ntext),开建立数据库中,对这四种类型往往比较模糊,这 ...