OKio 源码(1.x分支)分析记录(二)Sink输出数据

上一篇描述通过source从文件中读取数据,这篇主要描述通过Sink向文件中输出数据,Sink的意思是水槽,它对应着输出流

  • 先看下通过Sink输出到文件代码调用流程
File sinkFile = new File(path);
Sink sink = Okio.sink(sinkFile);
BufferedSink bufferedSink = Okio.buffer(sink);
---------------------------------------------------
bufferedSink.write(byte[]); //输出数据
  • Sink的对象创建流程

Sink的创建需要传入接收输出文件对象,Sink依赖一个文件对象,下面看下Sink创建流程

public static Sink sink(OutputStream out) {
        return sink(out, new Timeout());
    }
==>
 private static Sink sink(final OutputStream out, final Timeout timeout) {
        if (out == null) {
            throw new IllegalArgumentException("out == null");
        } else if (timeout == null) {
            throw new IllegalArgumentException("timeout == null");
        } else {
            return new Sink() {
                public void write(Buffer source, long byteCount) throws IOException {
                    Util.checkOffsetAndCount(source.size, 0L, byteCount);

                    while(byteCount > 0L) {
                        timeout.throwIfReached();
                        Segment head = source.head;
                        int toCopy = (int)Math.min(byteCount, (long)(head.limit - head.pos));
                        out.write(head.data, head.pos, toCopy);
                        head.pos += toCopy;
                        byteCount -= (long)toCopy;
                        source.size -= (long)toCopy;
                        if (head.pos == head.limit) {
                            source.head = head.pop();
                            SegmentPool.recycle(head);
                        }
                    }

                }

                public void flush() throws IOException {
                    out.flush();
                }

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

                public Timeout timeout() {
                    return timeout;
                }

                public String toString() {
                    return "sink(" + out + ")";
                }
            };
        }
    }

Sink是一个接口,OKio在创建时通过匿名内部类实现Sink接口定义方法,其中一个重要的方法是write方法,将Segment链表循环将数据输出到output对接中。

  • BufferSink的创建流程

 BufferSink是一个集成Sink的接口,OKio中通过new 一个RealBufferSink对象创建,具体代码如下,创建时需要传入一个Sink对象,RealBufferSink与Sink为组合关系。

public static BufferedSink buffer(Sink sink) {
        return new RealBufferedSink(sink);
}
-----------------------------------------------------

    RealBufferedSink(Sink sink) {
        if (sink == null) {
            throw new NullPointerException("sink == null");
        } else {
            this.sink = sink;
        }
    }

  • RealBufferedSink.write流程
    public BufferedSink write(byte[] source) throws IOException {
        if (this.closed) {
            throw new IllegalStateException("closed");
        } else {
            this.buffer.write(source);
            return this.emitCompleteSegments();
        }
    }

先看buffer.write(source)方法,RealBufferedSink类依赖Buffer,含有一个全局变量buffer,再下buffer.write方法

 public Buffer write(byte[] source) {
        if (source == null) {
            throw new IllegalArgumentException("source == null");
        } else {
            return this.write(source, 0, source.length);
        }
    }
---------------------------------------------------------------------------------
 public Buffer write(byte[] source, int offset, int byteCount) {
        if (source == null) {
            throw new IllegalArgumentException("source == null");
        } else {
            Util.checkOffsetAndCount((long)source.length, (long)offset, (long)byteCount);

            Segment tail;
            int toCopy;
            for(int limit = offset + byteCount; offset < limit; tail.limit += toCopy) {
                tail = this.writableSegment(1);
                toCopy = Math.min(limit - offset, 8192 - tail.limit);
                System.arraycopy(source, offset, tail.data, tail.limit, toCopy);
                offset += toCopy;
            }

            this.size += (long)byteCount;
            return this;
        }
    }
System.arraycopy(source, offset, tail.data, tail.limit, toCopy);将数据copy到一个Segment中,Segment从segment池中获取,返回一个buffer对象。

再看 return this.emitCompleteSegments()方法,重要的一个动作就是调用Sink的write方法,将Segment中数据写入outputString中 out.write(head.data, head.pos, toCopy);

完成输出数据的任务

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值