Android内核及各种干货开源项目实践与分析Android技术知识

Android下的IO库-Okio源码解析(肆)

2017-03-21  本文已影响45人  非墨Zero

本章非墨将给大家解析一下Okio中的BufferedSource和BufferedSink接口,我们对比jre里面的BufferedInputStream和BufferedOutputStream。实际上他们从功能上是一模一样的:

1.为了提高效率,减少IO中断频率
2.由于一次性读取更多的数据,因此可以对数据进行组合使用

我们先来看看Jdk里面是如何处理BufferStream的,以BufferedInputStream为例:

@Override
    public synchronized int read() throws IOException {
        // Use local refs since buf and in may be invalidated by an
        // unsynchronized close()
        byte[] localBuf = buf;
        InputStream localIn = in;
        if (localBuf == null || localIn == null) {
            throw streamClosed();
        }

        /* Are there buffered bytes available? */
        if (pos >= count && fillbuf(localIn, localBuf) == -1) {//一次性读取多个数据
            return -1; /* no, fill buffer */
        }
        // localBuf may have been invalidated by fillbuf
        if (localBuf != buf) {
            localBuf = buf;
            if (localBuf == null) {
                throw streamClosed();
            }
        }

        /* Did filling the buffer fail with -1 (EOF)? */
        if (count - pos > 0) {
            return localBuf[pos++] & 0xFF;
        }
        return -1;
    }

我们可以看到,在BufferedInputStream中,实际上是生成了一个buf数组,即使你一次性只是读取一个字节的数据,BufferedInputStream一样会通过一个buf(缓存)变量来读取多个的数据。这样当你在读取下一个数据的时候就可以直接在进程内的内存数据,而不涉及操作系统的系统调用。
我们再回到Okio中,之前我们说过,Okio的很多概念都可以对标jdk中的流,之间的映射关系基本如下表:

1.Source->InputStream
2.Sink->OutputStream
3.Buffer->byte[]
4.BufferedSource->BufferedInputStream
5.BufferedSink->BufferedOuputStream
有了以上的只是储备,我们可以更好的理解Okio的Buffered相关代码。

以BufferedSource为例,我们来看下Okio是如何实现的。BufferedSource本身是一个接口,我们可以通过接口定义看出它跟Source本身的区别:

Source本身只承担最为基本的数据读取,BufferedSource可以通过数据拼装成为各种的数据类型

public interface BufferedSource extends Source {
  /** Returns this source's internal buffer. */
  Buffer buffer();//Buffered内部自定义的Buffer对象

  /**
   * Returns true if there are no more bytes in this source. This will block until there are bytes
   * to read or the source is definitely exhausted.
   */
  boolean exhausted() throws IOException;//看下此Buffer是否耗尽

  /**
   * Returns when the buffer contains at least {@code byteCount} bytes. Throws an
   * {@link java.io.EOFException} if the source is exhausted before the required bytes can be read.
   */
  void require(long byteCount) throws IOException;//查看是否还有byteCount长度的字段

  /**
   * Returns true when the buffer contains at least {@code byteCount} bytes, expanding it as
   * necessary. Returns false if the source is exhausted before the requested bytes can be read.
   */
  boolean request(long byteCount) throws IOException;//请求byteCount长度的数据

  /** Removes a byte from this source and returns it. */
  byte readByte() throws IOException;
 ....
}

在Okio类的静态方法buffer中,构造了这个BufferedSource对象,而这个接口的实现类是RealBufferedSource的类:

public static BufferedSource buffer(Source source) {
    return new RealBufferedSource(source);
  }
final class RealBufferedSource implements BufferedSource {
  public final Buffer buffer = new Buffer();//内部定义的buffer
  public final Source source;//被装饰的source
  boolean closed;
....
}

我们着重看一下它的read()方法:

@Override public long read(Buffer sink, long byteCount) throws IOException {
    if (sink == null) throw new IllegalArgumentException("sink == null");
    if (byteCount < 0) throw new IllegalArgumentException("byteCount < 0: " + byteCount);
    if (closed) throw new IllegalStateException("closed");

    if (buffer.size == 0) {
      long read = source.read(buffer, Segment.SIZE);//从source中读入数据到内部的Buffer中
      if (read == -1) return -1;
    }

    long toRead = Math.min(byteCount, buffer.size);
    return buffer.read(sink, toRead);//从内部的buffer拷贝到sink目标buffer
  }

RealBufferedSource的做法,一样是先通过一个Buffer来预取数据,然后通过拷贝的方式拷贝到sink目标缓存中。

上一篇下一篇

猜你喜欢

热点阅读