Android下的IO库-Okio源码解析(肆)
本章非墨将给大家解析一下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目标缓存中。