标签:
上一节《OkHttp深入学习(三)——Cache》我们对okhttp中的Cache缓存机制进行了学习,学习了上一节的内容,如果叫我们自己去设计一个缓存机制,那么我们一定会有了自己的思路,想想还有点小激动。这一节我们继续来看看okhttp这个教科书中还有什么值得我们继续挖掘的东西。果不其然,我们发现了okio这个好东西,该类主要负责对java中io的封装,使得java中的io流读写更加方便,甚至还能提高读写效率。okio项目开源地址请戳这里。在正式学习之前,我们先来了解一下它是如何使用的,随后我们再根据涉及到的内容进行深入学习。static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; //很明显这个肯定是在进行hex解析的时候被使用到 final byte[] data; transient int hashCode; //说是String远方亲戚也不假,String也有类似上面的两个域 transient String utf8; //这个域的存在就是实现了对utf-8解码的优化,是一个对utf8解码String的优化
ByteString(byte[] data) { this.data = data; }
public static ByteString of(byte... data) { if (data == null) throw new IllegalArgumentException("data == null"); return new ByteString(data.clone());//note1 } public static ByteString of(byte[] data, int offset, int byteCount) { if (data == null) throw new IllegalArgumentException("data == null"); checkOffsetAndCount(data.length, offset, byteCount);//note2 byte[] copy = new byte[byteCount]; System.arraycopy(data, offset, copy, 0, byteCount);//note3 return new ByteString(copy); }
public String toString() { if (data.length == 0) { return "ByteString[size=0]"; } if (data.length <= 16) { return String.format("ByteString[size=%s data=%s]", data.length, hex()); } return String.format("ByteString[size=%s md5=%s]", data.length, md5().hex()); }
public String utf8() { String result = utf8; return result != null ? result : (utf8 = new String(data, Util.UTF_8)); }
static final int SIZE = 2048; //一个Segment存储的最大比特数据的数量 final byte[] data; //比特数组的引用 int pos; //pos第一个可以读的位置 int limit; //limit是第一个可以写的位置,所以一个Segment的可读数据数量为pos~limit-1=limit-pos;limit和pos的有效值为0~SIZE-1 boolean shared; //当前存储的data数据是其它对象共享的则为真 boolean owner; //是当前data的所有者 Segment next; //下一个Segment Segment prev; //前一个Segment
Segment() { this.data = new byte[SIZE]; this.owner = true; //note1 this.shared = false; //note2 } Segment(Segment shareFrom) { this(shareFrom.data, shareFrom.pos, shareFrom.limit); shareFrom.shared = true; //note3 } Segment(byte[] data, int pos, int limit) { this.data = data; this.pos = pos; this.limit = limit; this.owner = false; //note4 this.shared = true; //note5 }
public Segment pop() { Segment result = next != this ? next : null; prev.next = next; next.prev = prev; next = null; prev = null; return result; }
public Segment push(Segment segment) { segment.prev = this; segment.next = next; next.prev = segment; next = segment; return segment; }
public Segment split(int byteCount) { if (byteCount <= 0 || byteCount > limit - pos) throw new IllegalArgumentException(); Segment prefix = new Segment(this); prefix.limit = prefix.pos + byteCount; pos += byteCount; prev.push(prefix); return prefix; }
public void compact() { if (prev == this) throw new IllegalStateException(); if (!prev.owner) return; //note1 int byteCount = limit - pos; //note2 int availableByteCount = SIZE - prev.limit + (prev.shared ? 0 : prev.pos); //note3 if (byteCount > availableByteCount) return; //note4 writeTo(prev, byteCount); //note5 pop(); //note6 SegmentPool.recycle(this); //note7 }
public void writeTo(Segment sink, int byteCount) { if (!sink.owner) throw new IllegalArgumentException(); //note1 if (sink.limit + byteCount > SIZE) { //note2 if (sink.shared) throw new IllegalArgumentException(); //note3 if (sink.limit + byteCount - sink.pos > SIZE) throw new IllegalArgumentException(); //note4 System.arraycopy(sink.data, sink.pos, sink.data, 0, sink.limit - sink.pos); //note5 sink.limit -= sink.pos; sink.pos = 0; } System.arraycopy(data, pos, sink.data, sink.limit, byteCount);//note6 sink.limit += byteCount; pos += byteCount; }
static final long MAX_SIZE = 64 * 1024; // 大家是否还记得一个Segment记录的数据最大长度为2048?因此该Segment相当于能存储32个Segment对象。不过为何不是32*2048? static Segment next; //该SegmentPool存储了一个回收Segment的链表 static long byteCount; //该值记录当前存储的所有Segment总大小,最大值为MAX_SIZE
static Segment take() { synchronized (SegmentPool.class) { if (next != null) { Segment result = next; next = result.next; result.next = null; byteCount -= Segment.SIZE; return result; } } return new Segment(); // Pool is empty. Don't zero-fill while holding a lock. }
static void recycle(Segment segment) { if (segment.next != null || segment.prev != null) throw new IllegalArgumentException(); if (segment.shared) return; // This segment cannot be recycled. synchronized (SegmentPool.class) { if (byteCount + Segment.SIZE > MAX_SIZE) return; // Pool is full. byteCount += Segment.SIZE; segment.next = next; segment.pos = segment.limit = 0; next = segment; } }
static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; //很明显这个肯定是在进行hex解析的时候被使用到 Segment head; //Buffer存储了一个这样的head结点,这就是Buffer对数据的存储结构。字节数组都是交给Segment进行管理。 long size; //当前存储的数据的大小
public Buffer() { }
public Buffer copyTo(Buffer out, long offset, long byteCount) { if (out == null) throw new IllegalArgumentException("out == null"); checkOffsetAndCount(size, offset, byteCount); if (byteCount == 0) return this; out.size += byteCount; //note1 Segment s = head; for (; offset >= (s.limit - s.pos); s = s.next) { //note2 offset -= (s.limit - s.pos); } // note3 for (; byteCount > 0; s = s.next) { Segment copy = new Segment(s); copy.pos += offset; copy.limit = Math.min(copy.pos + (int) byteCount, copy.limit); if (out.head == null) { out.head = copy.next = copy.prev = copy; } else { out.head.prev.push(copy); } byteCount -= copy.limit - copy.pos; offset = 0; } return this; }
public int readInt() { if (size < 4) throw new IllegalStateException("size < 4: " + size); //note1 Segment segment = head; int pos = segment.pos; int limit = segment.limit; //note2 if (limit - pos < 4) { return (readByte() & 0xff) << 24 | (readByte() & 0xff) << 16 | (readByte() & 0xff) << 8 | (readByte() & 0xff); } //note3 byte[] data = segment.data; int i = (data[pos++] & 0xff) << 24 | (data[pos++] & 0xff) << 16 | (data[pos++] & 0xff) << 8 | (data[pos++] & 0xff); size -= 4; if (pos == limit) { //note4 head = segment.pop(); SegmentPool.recycle(segment); } else { segment.pos = pos; } return i; //note5 }
public byte readByte() { if (size == 0) throw new IllegalStateException("size == 0"); Segment segment = head; int pos = segment.pos; int limit = segment.limit; byte[] data = segment.data; byte b = data[pos++]; //note1 size -= 1; if (pos == limit) { //note2 head = segment.pop(); SegmentPool.recycle(segment); } else { segment.pos = pos; } return b; //note3 }
Source source(final InputStream in) { return source(in, new Timeout());} Source source(File file) throws FileNotFoundException{ return source(new FileInputStream(file)); } Source source(Path path, OpenOption... options) throws IOException { return source(Files.newInputStream(path, options)); } Source source(final Socket socket) throws IOException{ AsyncTimeout timeout = timeout(socket); Source source = source(socket.getInputStream(), timeout); return timeout.source(source); }
private static Source source(final InputStream in, final Timeout timeout) { if (in == null) throw new IllegalArgumentException("in == null"); if (timeout == null) throw new IllegalArgumentException("timeout == null"); return new Source() { @Override public long read(Buffer sink, long byteCount) throws IOException { if (byteCount < 0) throw new IllegalArgumentException("byteCount < 0: " + byteCount); if (byteCount == 0) return 0; timeout.throwIfReached();//note1 Segment tail = sink.writableSegment(1); //note2 int maxToCopy = (int) Math.min(byteCount, Segment.SIZE - tail.limit); //note3 int bytesRead = in.read(tail.data, tail.limit, maxToCopy); //note4 if (bytesRead == -1) return -1; tail.limit += bytesRead;//note5 sink.size += bytesRead; return bytesRead; } @Override public void close() throws IOException { in.close(); } @Override public Timeout timeout() { return timeout; } @Override public String toString() { return "source(" + in + ")"; } }; }
Sink sink(final OutputStream out) { return sink(out, new Timeout()); } Sink sink(File file) throws FileNotFoundException{ return sink(new FileOutputStream(file)); } Sink appendingSink(File file) throws FileNotFoundException{ return sink(new FileOutputStream(file, true)); } Sink sink(Path path, OpenOption... options) throws IOException{ return sink(Files.newOutputStream(path, options)); } Sink sink(final Socket socket) throws IOException{ AsyncTimeout timeout = timeout(socket); Sink sink = sink(socket.getOutputStream(), timeout); return timeout.sink(sink); }
public static Sink sink(final 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"); if (timeout == null) throw new IllegalArgumentException("timeout == null"); return new Sink() { @Override public void write(Buffer source, long byteCount) throws IOException { checkOffsetAndCount(source.size, 0, byteCount); while (byteCount > 0) { timeout.throwIfReached(); Segment head = source.head; //note1 int toCopy = (int) Math.min(byteCount, head.limit - head.pos);//note2 out.write(head.data, head.pos, toCopy); //note3 head.pos += toCopy;//note4 byteCount -= toCopy; source.size -= toCopy; if (head.pos == head.limit) {//note4 source.head = head.pop(); SegmentPool.recycle(head); } } } @Override public void flush() throws IOException { out.flush(); } @Override public void close() throws IOException { out.close(); } @Override public Timeout timeout() { return timeout; } @Override public String toString() { return "sink(" + out + ")"; } }; }
public static BufferedSource buffer(Source source) { if (source == null) throw new IllegalArgumentException("source == null"); return new RealBufferedSource(source); }
public RealBufferedSource(Source source) { this(source, new Buffer()); //note1 } public RealBufferedSource(Source source, Buffer buffer) { if (source == null) throw new IllegalArgumentException("source == null"); this.buffer = buffer; this.source = source; }
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) { //note1 long read = source.read(buffer, Segment.SIZE); if (read == -1) return -1; } long toRead = Math.min(byteCount, buffer.size); //note2 return buffer.read(sink, toRead); //note3 }
public int readInt() throws IOException { require(4); return buffer.readInt(); }
public void require(long byteCount) throws IOException { if (!request(byteCount)) throw new EOFException(); //没有读到要求的数据宝宝表示不开心,后果很严重 } public boolean request(long byteCount) throws IOException { if (byteCount < 0) throw new IllegalArgumentException("byteCount < 0: " + byteCount); if (closed) throw new IllegalStateException("closed"); while (buffer.size < byteCount) { if (source.read(buffer, Segment.SIZE) == -1) return false; //note1 } return true; }
public static BufferedSink buffer(Sink sink) { if (sink == null) throw new IllegalArgumentException("sink == null"); return new RealBufferedSink(sink); }
public RealBufferedSink(Sink sink) { this(sink, new Buffer()); } public RealBufferedSink(Sink sink, Buffer buffer) { if (sink == null) throw new IllegalArgumentException("sink == null"); this.buffer = buffer; this.sink = sink; }
public BufferedSink write(byte[] source) throws IOException { if (closed) throw new IllegalStateException("closed"); buffer.write(source);//note1 return emitCompleteSegments();//note2 }
public BufferedSink emitCompleteSegments() throws IOException { if (closed) throw new IllegalStateException("closed"); long byteCount = buffer.completeSegmentByteCount(); //note1 if (byteCount > 0) sink.write(buffer, byteCount); return this; }
public BufferedSink writeInt(int i) throws IOException { if (closed) throw new IllegalStateException("closed"); buffer.writeInt(i); //note1 return emitCompleteSegments(); //note2 }
public void flush() throws IOException { if (closed) throw new IllegalStateException("closed"); if (buffer.size > 0) { sink.write(buffer, buffer.size); } sink.flush(); }
标签:
原文地址:http://blog.csdn.net/evan_man/article/details/51204469