BufferedOutputStream的缓存功能解析(源码阅读)

[size=medium]要介绍BufferedOutputStream,我们先了解一下OutputStream类
抽象类OutputStream类有三个write方法[/size]

[b][size=medium][list=1]
[*]public abstract void write(int b)
[*]public void write(byte b[])
[*]public void write(byte b[], int off, int len)
[/list][/size][/b]
[size=medium]由上面我们可以看出第一个write方法是让子类覆盖的,而第二个人write(byte b[])方法源代码如下[/size]
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}

[size=medium]所以可见最后处理还是调用第三个方法write(byte b[],int off,int len),该方法源码如下:[/size]

public void write(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off 0) || (off > b.length) || (len 0) ||
((off + len) > b.length) || ((off + len) 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
for (int i = 0 ; i //注意这儿,这儿其实调用前面的抽象方法write(int b),同时还发生了自动转型
write(b[off + i]);
}
}

[size=medium][b]问题[/b] [/size]
[size=medium] 我们先不看抽象方法是如何实现的,也就是说OutputStream也具有缓存器功能,我们可以将要写入到流中的数据写到一个byte[] buf数组中,然后调用write(byte b[])或者write(byte b[], int off, int len)也可以,那为什么还要BufferedInputStream类干什么呢,他们有什么区别呢。同时我们知道BufferedInputStream类中还有一个flush()方法,在OutputStream流中没有flush()方法,这又是为什么呢?flush()是不是必须的呢,接下来看一下BufferedOutputStream类;[/size]
[size=medium]首先,BufferedOutput将OutputStream类对象作为一个构造方法的参数的。
首先看一下BufferedOutputStream 类源代码[/size]

public
class BufferedOutputStream extends FilterOutputStream {

//这儿定义了一个byte[]数组,用来充当缓存器
protected byte buf[];
//这个变量是重点,他就是用来记录当前缓存器中的字节数量的
protected int count;
//我们初始化创建一个对象的时候给了这个buf这个数组8192个字节.
public BufferedOutputStream(OutputStream out) {
this(out, 8192);
}

public BufferedOutputStream(OutputStream out, int size) {
super(out);
if (size 0) {
throw new IllegalArgumentException("Buffer size );
}
// 这儿创建一个给定大小的数组对象来充当缓存器
buf = new byte[size];
}

public synchronized void write(int b) throws IOException {
if (count >= buf.length) {
flushBuffer();
}
buf[count++] = (byte)b;
}

//该方法是重点
public synchronized void write(byte b[], int off, int len) throws IOException {
//如果传进来的数组长度大于buf 数组的长度,则直接调用OutputStream对象的write方法。
if (len >= buf.length) {

flushBuffer();
out.write(b, off, len);
return;
}
//验证BufferedOutputStream 类中buf剩下的空间能否装得下传进来的数组。如果不能则先将当前buf数组中数据写入底层io流中
if (len > buf.length - count) {
flushBuffer();
}
//该处是重点,如果在当前BufferedOutputStream 类中buf数组没有满,则将传进来的数组复制到当前类对象buf数组中,同时更新count的值。
System.arraycopy(b, off, buf, count, len);
count += len;
//调用flushBuffer方法也就是将不满8192个字节数组中的数据发送出去。同时将count置零。
private void flushBuffer() throws IOException {
if (count > 0) {
out.write(buf, 0, count);
count = 0;
}
}

//强制将buf数据中未满8192个字节的数据写入底层io中。
public synchronized void flush() throws IOException {
flushBuffer();
out.flush();
}
}


[size=medium][b]结论:[/b] [/size]
[size=medium]OutputStream的缓存器(数组)与BufferedOutputStream中类的缓存器(数组)本质是一样的,只是BufferedOutputStream类中将要写入到底层io流中的数据先凑个整,然后再一起写入底层io流中,这样就大大节省了io操作,大大提高了io利用率,写一次io是很费资源的。这样也出现了一个问题,假设向硬盘中写入一个文件,文件最后数据比默认值8192个字节小,则BufferOutputStream就不会将这些数据写入底层io流中,造成文件缺失,因此就需要在close()前调用flush()方法,强制将还没有装满buf数组的数据写入底层io中。同时也可以看出节点流是不用flush()方法的,而一般的处理流都会采用固定buf这种方式的,比如常用的PrintWriter里面其实操作的就是一个BufferedWriter对象,因此也需要调用flush()方法来刷新,因为默认是不刷新的。[/size]
[size=medium]
参考: [/size]
[url=http://www.bdqn.cn/news/201311/12111.shtml]http://www.bdqn.cn/news/201311/12111.shtml[/url]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值