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

作者: 非墨Zero | 来源:发表于2017-03-21 12:29 被阅读45次

    本章非墨将给大家解析一下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目标缓存中。

    相关文章

      网友评论

        本文标题:Android下的IO库-Okio源码解析(肆)

        本文链接:https://www.haomeiwen.com/subject/lswwnttx.html