Java IO mark() reset()

mark(int readLimit)这个地方对readLimit有些迷惑,API中是这么解释的

The readlimit arguments tells this input stream to allow that many bytes to be read before the mark position gets invalidated.

查看了一下源码,大致明白了一些。不想看源码的直接跳到最后。

BufferedInputStream源码:

先看几个属性:

protected volatile byte buf[]; 这是内部缓冲区,数据存储在这里面。

protected int pos; 这个属性用来标记buffer中的当前位置,即下一次read操作会从这个位置开始读取。

protected int markpos = -1; 这个用来记录我们mark操作时的pos值。

protected int marklimit; mark操作之后,read操作之前允许读取的最大值。

看一下mark函数:

public synchronized void mark(int readlimit) {
        marklimit = readlimit;
        markpos = pos;
}

很简单,就是存储mark时刻的状态。

看一下rese函数:

public synchronized void reset() throws IOException {
        getBufIfOpen(); // Cause exception if closed
        if (markpos < 0)
            throw new IOException("Resetting to invalid mark");
        pos = markpos;
}

也很简单,就是重新把指针移动到mark的地方,下次从此处开始读取。

下面看一下mark的参数readLimit

    private void fill() throws IOException {
        byte[] buffer = getBufIfOpen();
        if (markpos < 0)
            pos = 0;            /* 没有mark的情况 */
        else if (pos >= buffer.length)  /* no room left in buffer */
            if (markpos > 0) {  //
                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 {            /* grow buffer */
                int nsz = pos * 2;
                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;
    }

上面的代码是用来填充缓冲区的,流程是这样的:如果没有mark()标记,可以直接填充;如果有mark标记,但是当前的pos位置小于缓冲区的长度,即缓冲区未填满,那么继续填充剩余的缓冲区;如果当前的pos已经到达缓冲区末尾,这时的操作取决于mark的位置,如果mark的位置大于0,那么缓冲区中mark之前的就没用了,直接复制markpos到缓冲区末尾的数据给当前的缓冲区;如果makpos等于0,这时分两种情况,如果缓冲区长度大于等于marklimit,这时相当于marklimit是无效的,因为可用数据比我们的marklimit还要大,肯定符合要求;如果缓冲区长度小于marklimit,这时因为markpos等于0,我们需要的缓冲区长度是marklimit-markpos=marklimit>bufferLength,所以缓冲区需要扩展了。

一句话解释一下:因为缓冲区大小是固定的,在某一位置mark之后,如果又进行了大量数据的读写,整个缓冲区可能因为被完全冲刷掉而导致无法进行后续的reset操作,这时调用reset就会抛出异常。相比之下ByteArrayInputStream就不会产生这个问题,因为它所有的数据都在内存中,不存在被冲刷的情况。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值