OKio 源码(1.x分支)分析记录(一)Source读取数据

  • 工程说明okio是Square开源框架 之一,它对java.io和java.nio做了补充,使访问,存储和数据处理变得更加容易。它最早是Okhttp组件之一
  • 分支说明:本文选取1.x分支源码(JAVA代码)分析
  master
* okio_1x
  remotes/origin/HEAD -> origin/master
  remotes/origin/egorand/200216/buffer-nsdata
  remotes/origin/gh-pages
  remotes/origin/ghpages-javadocs
  remotes/origin/jakew/top-level-common/2019-04-04
  remotes/origin/jwilson.0207.zip
  remotes/origin/jwilson.0209.zipzip
  remotes/origin/jwilson.0306.relative_list
  remotes/origin/jwilson.0424.arrays
  remotes/origin/jwilson.0515.windows_file_handle
  remotes/origin/jwilson.0523.js
  remotes/origin/jwilson.0601.toFraction_toIndex
  remotes/origin/jwilson.0722.copyInto
  remotes/origin/jwilson.0723.aoobe_rm
  remotes/origin/jwilson.1101.coroutines
  remotes/origin/master
  remotes/origin/okio_1_14
  remotes/origin/okio_1x
  remotes/origin/okio_2_4
  remotes/origin/okio_2x
  remotes/origin/ray/new-hotness-structure
  • 按照使用代码流程分析源码实现过程

    Okio包含自己的流类型,称为Source和Sink,其工作方式虽然类似InputStream和OutputStream,但它与Java I/O相比具有以下优势(参考自Android学习笔记——Okio):

  •    Okio实现了I/O读写的超时机制(Timeout),防止读写出错从而导致一直阻塞。
  •     N合一,OKIO精简了输入输出流的类个数
  •     低的CPU和内存消耗,引入Segment和SegmentPool复用机制
  •     使用方便。ByteString处理不变byte,Buffer处理可变byte。
  •     提供了一系列的工具。OKIO支持md5、sha、base64等数据处理

Source、Sink可以与InputStream、OutputStream互相操作。我们可以将任何Source视为InputStream,也可以将任何InputStream视为Source。同样适用于Sink和InputStream。

            //从文件读取数据
            File sourceFile = new File("path");
            Source source = Okio.source(sourceFile);
            BufferedSource bufferedSource = Okio.buffer(source);
            byte[] allByte = bufferedSource.readByteArray();

1、先看OKio.source(sourceFile),此方法中返回了一个匿名内部类,实现read、close等方法,依赖InputString对象;read函数中主要从inputStream中读取最大8Kb大小数据的内容;

    public static Source source(File file) throws FileNotFoundException {
        if (file == null) {
            throw new IllegalArgumentException("file == null");
        } else {
            return source((InputStream)(new FileInputStream(file)));
        }
    }


 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() {
                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();
                            Segment tail = sink.writableSegment(1);
                            int maxToCopy = (int)Math.min(byteCount, (long)(8192 - tail.limit));
                            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 + ")";
                }
            };
        }
    }

2、BufferedSource bufferedSource = Okio.buffer(source)代码流程,OKio.buffer代码如下,buffer是一个接口,真正返回一个RealBufferedSource(source)对象;

public static BufferedSource buffer(Source source) {
        return new RealBufferedSource(source);
    }

3、byte[] allByte = bufferedSource.readByteArray()代码流程,RealBufferedSource.readByteArray(),

  1. writeAll函数的作用是从inputStream对接中读取所有数据,并通过segment链表保存;
  2. buffer.readByteArray(),从上面保存的segment中copy数据到byte[ ]数组,具体由代码(2)(3)(4)三个函数实现,readFully(byte[] result)for循环从segment链表中获取数据;
    public byte[] readByteArray() throws IOException {
        this.buffer.writeAll(this.source);
        return this.buffer.readByteArray();
    }
---------------------------------------(1)-------------------------------------------
    public long writeAll(Source source) throws IOException {
        if (source == null) {
            throw new IllegalArgumentException("source == null");
        } else {
            long totalBytesRead;
            long readCount;
            for(totalBytesRead = 0L; (readCount = source.read(this, 8192L)) != -1L; totalBytesRead += readCount) {
            }

            return totalBytesRead;
        }
    }
---------------------------------------(2)-------------------------------------------
    public byte[] readByteArray() {
        try {
            return this.readByteArray(this.size);
        } catch (EOFException var2) {
            throw new AssertionError(var2);
        }
    }
---------------------------------------(3)-------------------------------------------
    public byte[] readByteArray(long byteCount) throws EOFException {
        Util.checkOffsetAndCount(this.size, 0L, byteCount);
        if (byteCount > 2147483647L) {
            throw new IllegalArgumentException("byteCount > Integer.MAX_VALUE: " + byteCount);
        } else {
            byte[] result = new byte[(int)byteCount];
            this.readFully(result);
            return result;
        }
    }
----------------------------------------(4)------------------------------------------
    public void readFully(byte[] sink) throws EOFException {
        int read;
        for(int offset = 0; offset < sink.length; offset += read) {
            read = this.read(sink, offset, sink.length - offset);
            if (read == -1) {
                throw new EOFException();
            }
        }

    }
-----------------------------------------(5)-----------------------------------------
    public int read(byte[] sink, int offset, int byteCount) {
        Util.checkOffsetAndCount((long)sink.length, (long)offset, (long)byteCount);
        Segment s = this.head;
        if (s == null) {
            return -1;
        } else {
            int toCopy = Math.min(byteCount, s.limit - s.pos);
            System.arraycopy(s.data, s.pos, sink, offset, toCopy);
            s.pos += toCopy;
            this.size -= (long)toCopy;
            if (s.pos == s.limit) {
                this.head = s.pop();
                SegmentPool.recycle(s);
            }

            return toCopy;
        }
    }

4、到此已完成source怎么从FileInputStream中获取数据并返回到byte数组的源码分析,下一篇分析Sink输出数据流程

参考博客:https://blog.csdn.net/lmh_19941113/article/details/86726961

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值