FileInputStream、OutPutStream和BufferedInputStream、BufferedOutputStream的效率问题

大家可能都知道带Buffered的IO流应该比普通的IO流更有效率,因为带Buffer的IO流就是为效率而创造出来的,而实际可能并不是在任何情况下都会这样。

在使用Buffer上,实际FileInputStream和BufferedFileInputStream并没有区别,为什么呢,先看如下一段使用BufferedFileInputStream的代码:

            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
            byte[] buffer = new byte[bufferSize];
            int copySize = 0;
            while((copySize=bis.read(buffer))>0){
                bis.write(buffer,0,bufferSize);
                //bis.flush();
            }

一般大家看到这样的代码,会认为自己的BufferedInputStream使用了缓冲区,确实,它使用了缓冲区,但这个缓冲区是我们自己定义的即这段程序:

 byte[] buffer = new byte[bufferSize];
并非是BufferedInputStream自己内部的缓冲区buf[],这个buf[]在源码中如下:

public
class BufferedInputStream extends FilterInputStream {

    private static int DEFAULT_BUFFER_SIZE = 8192;

    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;

    /**
     * The internal buffer array where the data is stored. When necessary,
     * it may be replaced by another array of
     * a different size.
     */
    protected volatile byte buf[];

之所以这么说,是因为在使用read(byte[] buffer)上,BufferedInputStream和FileInputStream没有任何区别,因为read(byte[] buffer)方法就是BufferedInputStream继承自FileInputStream的。

所以Buffer类的IO流在效率上比普通IO流要高主要体现在输出流上,输入流上没有差别,原因如下:

1. FileOutputStream的Write方法是直接的IO流,没有用到缓冲区:

    public void write(byte b[], int off, int len) throws IOException {
        writeBytes(b, off, len, append);
    }
    private native void writeBytes(byte b[], int off, int len, boolean append)
        throws IOException;
可以从源码中看到,write方法调用的是wireBytes方法,这是一个native的方法,直接去操作系统了。

2. BufferOutputStream的Write方法是用到了缓冲区的,在某些情况下效率会更高(某些情况下效率会更低,本文后面说明):

    public synchronized void write(byte b[], int off, int len) throws IOException {
        if (len >= buf.length) {
            /* If the request length exceeds the size of the output buffer,
               flush the output buffer and then write the data directly.
               In this way buffered streams will cascade harmlessly. */
            flushBuffer();
            out.write(b, off, len);
            return;
        }
        if (len > buf.length - count) {
            flushBuffer();
        }
        System.arraycopy(b, off, buf, count, len);
        count += len;
    }
从源码中可以看到,BufferedOutputStream在wirte时,会先判断要写的数据是否大于自己的缓冲区,大于缓冲区则直接flush缓冲区和数据,小于缓冲区则往缓冲区装,直到装不下了再flush缓冲区。当然,最后的Write还是调用FileOutputStream的write方法来实现,只不过用了缓冲区后减少了IO次数。

而这样做就是否在任何情况下都能提高效率呢?不是的!

因为BufferedOutputStream的缓冲区大小上面是有讲究的。默认的大小是8192即8k,如果在BufferedInputStream中一次读入的数据远远小于8K(即上文中我们提到的自定义缓冲区bufferSize的大小),BufferedOutputStream比FileOutputStream是有优势的,因为BufferedOutputStream明显IO次数要比FileOutputStream小,越小则BufferedOutputStream的优势越明显。

经实验证实:

1. bufferSize在4096及以下,BufferedOutputStream是有优势的

2. bufferSize在4097-8191之间,FilOutputSteam反而效率更高,因为在这一段2者的IO次数差不多,而BufferedOutputStream要操作2次缓冲区后才能flush

3. bufferSize大于等于8192时,BufferedOutputStream和FilOutputSteam效率就基本一样了







  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值