okio篇2-RealBufferedSource

10 篇文章 0 订阅
4 篇文章 0 订阅

上一篇讲过,okio只有两个概念,source和sink。source对应InputStream,即负责将数据读出,是一个输出方(所以只有source.read方法)。sink对应outputStream,负责获取数据写入,是一个写入方(所以只有sink.write方法)。而对于,source.read(sink)这个方法,实际就是,将source中的数据读出,写入到sink当中。

所以其实source和sink只有数据的流向不一致。所以,这里只介绍了RealBufferedSource,实际是跟RealBufferedSink是一致的。

介绍RealBufferedSource,首先先看下okio的基础用法。

public void readFileUseOkIo() {
    try {
        BufferedSource source = Okio.buffer(Okio.source(new File(fileName)));
        String content;
        while ((content = source.readUtf8Line()) != null) {
            System.out.println("readFileUseOkIo content:"+content);
        }
        source.close();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

注意,一般对应okio,只有两个常用的api,okio.source和okio.buffer方法。

这一行的实际含义是:

创建new File,内部创建new FileInputStream,作为source对应的inputStream。

再调用buffer,将source传入RealBufferedSource。RealBufferedSource同时维护一个Buffer,和一个Source。

Okio.source

source方法接收一个InputStream。并返回一个新创建的Source,重写了read(Buffer,long)方法。

这个方法在哪里会被调用到呢?后面会讲到。先记住source方法实际是重写了read(Buffer,long)方法。

// Okio.Source
private static Source source(final InputStream in, final Timeout timeout) {
    if (in == null) {
        throw new IllegalArgumentException("in == null");
    } else if (timeout == null) {
        throw new IllegalArgumentException("timeout == null");
    } else {
        return new Source() {
            // 这里实际上,是从source中的buffer转移数据到sink当中,如果source中没有数据了,
            // 就从in中读取数据到source中的buffer
            public long read(Buffer sink, long byteCount) throws IOException {
                if (byteCount < 0L) {
                    throw new IllegalArgumentException("byteCount < 0: " + byteCount);
                } else if (byteCount == 0L) {
                    return 0L;
                } else {
                    try {
                        timeout.throwIfReached();
                        // 从sink中获取一个可写的segment
                        Segment tail = sink.writableSegment(1);
                        int maxToCopy = (int)Math.min(byteCount, (long)(8192 - tail.limit));
                        // 从in中获取tail中可容纳的空间个字节到tail中
                        int bytesRead = in.read(tail.data, tail.limit, maxToCopy);
                        if (bytesRead == -1) {
                            return -1L;
                        } else {
                            tail.limit += bytesRead;
                            sink.size += (long)bytesRead;
                            return (long)bytesRead;
                        }
                    } catch (AssertionError var7) {
                        if (Okio.isAndroidGetsocknameError(var7)) {
                            throw new IOException(var7);
                        } else {
                            throw var7;
                        }
                    }
                }
            }

            public void close() throws IOException {
                in.close();
            }

            public Timeout timeout() {
                return timeout;
            }

            public String toString() {
                return "source(" + in + ")";
            }
        };
    }
}

Okio.buffer

// Okio.buffer方法
public static BufferedSource buffer(Source source) {
    return new RealBufferedSource(source);
}

Okio.buffer方法,只简单返回了RealBufferSource方法。

RealBufferedSource实际上是一个Source类型,内部维护了一个Buffer和一个Source。这个Source参数,实际就是刚才okio.source方法新创建的new Source,这个source重写了read(Buffer,long)方法。

// RealBufferedSource.read
// 两个Buffer之间转移,比如Source.read(Sink,byteCount)的时候,会调用这个方法
public long read(Buffer sink, long byteCount) throws IOException {
    if (sink == null) {
        throw new IllegalArgumentException("sink == null");
    } else if (byteCount < 0L) {
        throw new IllegalArgumentException("byteCount < 0: " + byteCount);
    } else if (this.closed) {
        throw new IllegalStateException("closed");
    } else {
        long read;
        if (this.buffer.size == 0L) {// 从这里看出,实际就是先从source读Segment.Size个字节的数据到buffer
        // 注意这里,这里实际是okio.source方法那里重写的read方法
        // 即这里,如果buffer内数据为空,就会调用stream.read方法,将数据读到buffer,即RealBufferedSource也是一个缓冲区。
            read = this.source.read(this.buffer, 8192L);
            if (read == -1L) {
                return -1L;
            }
        }

        read = Math.min(byteCount, this.buffer.size);
        // 然后再从buffer读取read个字节的数据到sink。一次最多只读取一个Segment的数据
        return this.buffer.read(sink, read);
    }
}

RealBufferedSource方法也重写了read(Buffer,long)。这个方法一般用于buffer间的数据交互,比如source的buffer数据,转移到sink的buffer中。

从上面的注释可以看出:

RealBufferSource中持有Source(Stream)和Buffer,Buffer相当于Source的缓冲区,Sink直接跟Buffer进行数据交互。当Buffer中数据被读取完了,Buffer会从Source中读数据。

也即:

总结

okio对外暴露的接口:okio.source和okio.buffer。

其中okio.source,构建了stream到buffer的数据流向。

而okio.buffer,创建了RealBufferedSource。RealBufferedSource维护一个buffer。当需要将数据传给sink的时候,优先从buffer中读取数据到sink。如果buffer为空,就会调用okio.source的方法,从stream中读取数据到buffer。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值