`
xinyiwust
  • 浏览: 13134 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

BufferedInputStream中的fill函数

    博客分类:
  • java
阅读更多
BufferedInputStream内用有一个很重要的private函数fill(),这个函数的原型如下:
[code="java"]    private void fill() throws IOException {
        byte[] buffer = getBufIfOpen();
if (markpos = 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 { /* 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;
    }

众所周知,BufferedInputStream会缓存一部分数据(默认8K),这个函数的作用就是读取更多的数据到缓存,必要的时候会扩大缓存的内容。
讲解这个函数前,先了解一下BufferedInputStream中一些字段的含义:

如图所示,矩形的长度表示buf的长度,count表示buf中的可读数据长度,pos表示当前已读取到的位置,markpos表示上一次调用mark函数时pos的位置,如果没调用过mark函数,则为-1。marklength的含义是,在调用reset函数的时候,marklength范围内的缓存必须被保留,注意marklength不能大于marklimit(marklimit是缓存中容许保留的最大长度)。
下面开始解读这个函数:
getBufIfOpen是获取当前buf的引用;
if (markpos < 0)
    pos = 0;
这句说明buf中没做过标记,没有数据需要保留,可以直接清空缓存buf;
else if (pos >= buffer.length)
这一句有两层含义:首先说明缓存中可能(注意,是可能)有数据需要保留,
同时说明缓存中已经没有可用的空间;
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;
    }
这一段代码,是处理缓存中确实有数据要保留的情况,首先计算需要保留的数据
占用的空间int sz = pos - markpos;
然后将它们copy到缓存的头部System.arraycopy(buffer, markpos, buffer, 0, sz);
再将当前位置设置到(pos-markpos),markpos设置到缓存的起始位置;
else if (buffer.length >= marklimit) {
markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */
    }
如果marklimit的值小于缓存的长度,说明buffer很大,从内存使用的角度考虑,此时
不宜再增大缓存的容量,在这种情形下直接丢弃buf中的已有内容;
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;
    }
如果缓存的容量不是很大,则扩大一倍(int nsz = pos * 2),因为此时markpos为-1,
所以将0到pos的数据保留(System.arraycopy(buffer, 0, nbuf, 0, pos)),下面的if
语句是使用了原子变量引用更新,确保多线程环境下内存的可见性;
       count = pos;
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
        if (n > 0)
            count = n + pos;
上面的代码是将缓存尽量的读满,并重新设置可读数据的长度count。


  • 大小: 20.5 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics