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. Devexpress VCL Build v2013 vol 14.1.3 发布

    我修,我修,修修修. New Major Features in 14.1 What's New in VCL Products 14.1 Breaking Changes To learn abou ...

  2. hdu-1050(贪心+模拟)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1050 思路:由图可知,1对应2,3对应4,以此类推,如果x,y是偶数则变为奇数: 每次输入两个区间,找 ...

  3. hdu -1114(完全背包)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1114 思路:求出存钱罐装全部装满情况下硬币的最小数量,即求出硬币的最小价值.转换为最小背包的问题. # ...

  4. 批处理(bat)的注释方法

    前面两个批处理教程的转贴,写得实在是太好了,内容详实,语言风趣,举例清晰.说实话,原作者幽默的文风用来写 批处理教程,而不是写文学小说,实在是有些屈才,但这样优秀的教程,用在枯燥乏味的程序事业里,确实 ...

  5. (KMP)剪花布条 -- hdu -- 2087

    http://acm.hdu.edu.cn/showproblem.php?pid=2087 剪花布条 Time Limit: 1000/1000 MS (Java/Others)    Memory ...

  6. 【OSGI】1.初识OSGI-到底什么是OSGI

    目前,业内关于OSGI技术的学习资源或者技术文档还是很少的.我在某宝网搜索了一下“OSGI”的书籍,结果倒是有,但是种类少的可怜,而且几乎没有人购买. 因为工作的原因我需要学习OSGI,所以我不得不想 ...

  7. web.xml中Filter,Listener,Servlet的区别

    一.Servlet Servlet是基本的服务端程序,他来自接口Servlet,接口中有方法service.而Servlet的一个重要实现类,则是tomcat服务器的核心,那就是HttpServlet ...

  8. Win10系统下编译OSG3.4

    环境说明 1.Win10专业版.64位: 2.VS2012旗舰版:QT5.2.0: 3.cmake-3.9.0.64位: 资源准备 1.OSG3.4源码包 http://trac.opensceneg ...

  9. .NET 调试入门(三)常用的命令

    windbg ANSI Command Tree 1.0 title {"Crash Dump Analysis Checklist"} body {"Crash Dum ...

  10. CentOS 7 安装MySQL 8.0.11

    1. 下载安装包 wget https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.13-1.el7.x86_64.rpm-bundle.tar 下载 ...