简单研究BufferedInputStream

FileInputstream

FileInputstream提供读取文件数据的方法,他们底层调用的是native方法

  1. native read0() 每次读出1个字节
  2. native int readBytes(byte b[], int off, int len) 读出数据到b字节数组中,并可以指定off【开始写入的位置】,【len】可最大读入len个字节到b数组, 返回【int】表示本次读取了几个字节
private native int read0() throws IOException;
private native int readBytes(byte b[], int off, int len) throws IOException;
public int read() throws IOException {
   return read0();
}
    //将数据读入数组,返回读取的个数
public int read(byte b[]) throws IOException {
    return readBytes(b, 0, b.length);
}
//off:读入的数据先放在off开始的地方,最多放入len个byte【读入的数据可能比len少】
public int read(byte b[], int off, int len) throws IOException {
    return readBytes(b, off, len);
}

BufferedInputStream

public class BufferedInputStream extends FilterInputStream
【BufferedInputStream 继承 FilterInputStream】
先来看BufferedInputStream 和 FilterInputStream 构造方法

public BufferedInputStream(InputStream in) {
    this(in, DEFAULT_BUFFER_SIZE);
}
public BufferedInputStream(InputStream in, int size) {
	//去FilterInputStream
    super(in);
    if (size <= 0) {
        throw new IllegalArgumentException("Buffer size <= 0");
    }
    buf = new byte[size];
}
public class FilterInputStream extends InputStream {

    protected volatile InputStream in;

    protected FilterInputStream(InputStream in) {
        this.in = in;
    }
}

发现:构造BufferedInputStream对象的过程中需要一个InputStream类型,并会生成一个byte[] buf
数组的大小我们可自己指定,也可以不指定,使用默认大小DEFAULT_BUFFER_SIZE= 8192

buf数组的奥妙

重点代码

protected int markpos = -1;
protected int pos;//当前应该读取字节的位置
protected int marklimit;
protected int count;//读取的最终位置

public synchronized int read() throws IOException {
    if (pos >= count) {
        fill(); // 填充数组
        if (pos >= count)
            return -1;
    }
    return getBufIfOpen()[pos++] & 0xff;// pos指向的地方还没读取
}

    
private void fill() throws IOException {
    byte[] buffer = getBufIfOpen();
    if (markpos < 0)
        pos = 0;            /* no mark: throw away the buffer */
    else if (pos >= buffer.length)  /* no room left in buffer */
        if (markpos > 0) {  /* can throw away early part of the buffer */
            int sz = pos - markpos;
            System.arraycopy(buffer, markpos, buffer, 0, sz);
            pos = sz;
            markpos = 0;
        } else if (buffer.length >= marklimit) {
            markpos = -1;   /* buffer got too big, invalidate mark */
            pos = 0;        /* drop buffer contents */
        } else if (buffer.length >= MAX_BUFFER_SIZE) {
            throw new OutOfMemoryError("Required array size too large");
        } else {            /* grow buffer */
            int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
                    pos * 2 : MAX_BUFFER_SIZE;
            if (nsz > marklimit)
                nsz = marklimit;
            byte nbuf[] = new byte[nsz];
            System.arraycopy(buffer, 0, nbuf, 0, pos);
            if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
                // Can't replace buf if there was an async close.
                // Note: This would need to be changed if fill()
                // is ever made accessible to multiple threads.
                // But for now, the only way CAS can fail is via close.
                // assert buf == null;
                throw new IOException("Stream closed");
            }
            buffer = nbuf;
        }
    	count = pos;
    	int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
   		if (n > 0)
        count = n + pos;
}

先介绍方法getBufIfOpen()和getInIfOpen()

getBufIfOpen() :如果buf数组不为null, 就返回buf数组。否则抛异常new IOException(“Stream closed”)告诉你流关闭了

getInIfOpen() :如果inputstream不为null, 就返回inputstream。否则抛异常new IOException(“Stream closed”)告诉你流关闭了

假设buf数组长度是5,在第一次调用read函数的时候,他先通过InputStream读取多个字节保存在buf数组中。
在这里插入图片描述
然后返回getBufIfOpen()[pos++] & 0xff,他会将pos处的字节返回给你,第一次会返回pos=0处的字节。然后将pos++, 指向数组的下一个位置。
在这里插入图片描述

如果你第二次调用read(),程序先判断【pos >= count】
因为pos<count, 说明数组中还有未读的字节,不需要填充数组!直接返回
getBufIfOpen()[pos++] & 0xff,即将pos=1处的字节返回。

如果pos>=count,说明buf数组的内容全部读取完毕,接下来再次调用fill方法从inputstream中读取一些数据到buf中。

在这里插入图片描述

比较

FileInputstream支持单字节读取,他是真实的单字节读取,读取一个字节就进行了一次磁盘IO

BufferedInputStream会通过FileInputstream进行一次磁盘IO, 一口气读取多个数据先到自己的buf数组中【这样数据就在内存中】,后面即使你只读取1个字节,直接去buf中慢慢取。这样会减少直接对文件的IO,因为读取内存的数据更快。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

forgetable tree

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值