字节流,缓冲流(copy文件测试)及装饰者模式

一.案例

以下案例包含4个测试函数:

  • 单字节的字节流
  • 数组的字节流
  • 单字节的缓冲流
  • 数组的缓冲流

文件数据为15MB左右。

import java.io.*;

public class IO_test {
    // 单字节的字节流
    public static void copy(File in, File out) throws IOException {
        InputStream is = new FileInputStream(in);
        OutputStream os = new FileOutputStream(out);
        int by = 0;
        while ((by = is.read()) != -1) {
            os.write(by);
        }
        is.close();
        os.close();
    }
    
    // 数组的字节流
    public static void copy_batch(File in, File out) throws IOException {
        InputStream is = new FileInputStream(in);
        OutputStream os = new FileOutputStream(out);
        byte[] array = new byte[1024];
        int len = 0;
        while ((len = is.read(array)) != -1) {
            os.write(array,0,len);
        }
        is.close();
        os.close();
    }
    
    // 单字节的缓冲流
    public static void bufferedCopy(File in, File out) throws IOException {
        BufferedInputStream bi = new BufferedInputStream(new FileInputStream(in));
        BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(out));
        int by = 0;
        while ((by = bi.read()) != -1) {
            bo.write(by);
            bo.flush();
        }
        bo.close();
        bi.close();
    }
    
    // 数组的缓冲流
    public static void bufferedCopy_batch(File in, File out) throws IOException {
        BufferedInputStream bi = new BufferedInputStream(new FileInputStream(in));
        BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(out));
        byte[] array = new byte[1024];
        int len = 0;
        while ((len = bi.read(array)) != -1) {
            bo.write(array,0,len);
            bo.flush();
        }
        bo.close();
        bi.close();
    }
    
    public static void main(String[] args) throws IOException {
        File data = new File("E:\\test.mp4");
        File a = new File("E:\\test2.mp4");
        File b = new File("E:\\test3.mp4");
        File c = new File("E:\\test4.mp4");
        File d = new File("E:\\test5.mp4");

        long start = System.currentTimeMillis();
        copy(data, a);
        long end = System.currentTimeMillis();

        long start2 = System.currentTimeMillis();
        copy_batch(data, b);
        long end2 = System.currentTimeMillis();

        long start3 = System.currentTimeMillis();
        bufferedCopy(data, c);
        long end3 = System.currentTimeMillis();

        long start4 = System.currentTimeMillis();
        bufferedCopy_batch(data, d);
        long end4 = System.currentTimeMillis();

        System.out.println("单字节的字节流耗时:" + (end - start) + " ms");
        System.out.println("数组的字节流耗时:" + (end2 - start2) + " ms");
        System.out.println("单字节的缓冲流耗时:" + (end3 - start3) + " ms");
        System.out.println("数组的缓冲流耗时:" + (end4 - start4) + " ms");
    }
}

运行结果:

单字节的字节流耗时:67970 ms
数组的字节流耗时:92 ms
单字节的缓冲流耗时:38420 ms
数组的缓冲流耗时:60 ms

二.问题解决

单字节的缓冲流为什么这么慢

上方的单字节的缓冲流耗时:38420 ms,太长了。

因为执行了同步的flush(),去掉后变为 90ms。

其实感觉没必要写flush(),看源码中write(),自带了flushBuffer()操作:

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


private void flushBuffer() throws IOException {
    if (count > 0) {
        out.write(buf, 0, count);
        count = 0;
    }
}

数组的缓冲流到底是什么鬼

单字节的缓冲流其实是用到了BufferedInputStream类中的数组。

public synchronized int read() throws IOException {
    if (pos >= count) {   //当buf中已经缓存的字节都读取完了,那么将输入流的数据继续读入缓存buf中.
        fill();
        if (pos >= count)     //当发现输入流已经读取完毕了,那么退出.
            return -1;
    }
    return getBufIfOpen()[pos++] & 0xff;
}

private void fill() throws IOException {
//省略...
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
//省略...

点击read(buffer, pos, buffer.length - pos)这个函数,跳到了InputStream类下实现的read()。

有个问题,案例中第四个方法bufferedCopy_batch中read()函数传递进去的是一个数组,就有个疑问,BufferedInputStream中不是有数组当作缓存么,怎么又传进去一个数组,什么鬼?

原来,调用的不是BufferedInputStream下的read(),而是FilterInputStream下的。然后再点击,跳到了InputStream类下实现的read()。

class FilterInputStream extends InputStream {

    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }

}

其实说了这么多,原来不管BufferedInputStream中的read()函数,传进去的是字节还是数组,原理一样。不同的是前面用的BufferedInputStream自带的数组,后者用的自己的数组当作缓存。

装饰者模式是什么东西

虽然java的IO很复杂,但是学懂了其实很简单。
在这里插入图片描述
很多InputStream的实现类FileInputStream等等,这些类如果都要加同样的属性或者方法,则每个类下都要继承一个类来增添这些东西。会造成类太多。

FilterInputStream这个类就用来装饰,把要加的同样的属性或者方法写在BufferedInputStream这个类里,InputStream的实现类的实例(比如FileInputStream)传入到BufferedInputStream中,通过使用BufferedInputStream,则每个实例都能用到加的同样的属性或者方法。减少了冗余。

三.参考文章

缓存字节流BufferedInputStream使用及原理解析

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值