本章非墨將給大家解析一下Okio中的BufferedSource和BufferedSink接口,我們對比jre里面的BufferedInputStream和BufferedOutputStream淮逊。實際上他們從功能上是一模一樣的:
1.為了提高效率,減少IO中斷頻率
2.由于一次性讀取更多的數(shù)據(jù),因此可以對數(shù)據(jù)進行組合使用
我們先來看看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) {//一次性讀取多個數(shù)據(jù)
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數(shù)組,即使你一次性只是讀取一個字節(jié)的數(shù)據(jù),BufferedInputStream一樣會通過一個buf(緩存)變量來讀取多個的數(shù)據(jù)饥伊。這樣當(dāng)你在讀取下一個數(shù)據(jù)的時候就可以直接在進程內(nèi)的內(nèi)存數(shù)據(jù),而不涉及操作系統(tǒng)的系統(tǒng)調(diào)用戴甩。
我們再回到Okio中,之前我們說過,Okio的很多概念都可以對標(biāo)jdk中的流,之間的映射關(guān)系基本如下表:
1.Source->InputStream
2.Sink->OutputStream
3.Buffer->byte[]
4.BufferedSource->BufferedInputStream
5.BufferedSink->BufferedOuputStream
有了以上的只是儲備,我們可以更好的理解Okio的Buffered相關(guān)代碼停忿。
以BufferedSource為例,我們來看下Okio是如何實現(xiàn)的。BufferedSource本身是一個接口,我們可以通過接口定義看出它跟Source本身的區(qū)別:
Source本身只承擔(dān)最為基本的數(shù)據(jù)讀取,BufferedSource可以通過數(shù)據(jù)拼裝成為各種的數(shù)據(jù)類型
public interface BufferedSource extends Source {
/** Returns this source's internal buffer. */
Buffer buffer();//Buffered內(nèi)部自定義的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長度的數(shù)據(jù)
/** Removes a byte from this source and returns it. */
byte readByte() throws IOException;
....
}
在Okio類的靜態(tài)方法buffer中,構(gòu)造了這個BufferedSource對象,而這個接口的實現(xiàn)類是RealBufferedSource的類:
public static BufferedSource buffer(Source source) {
return new RealBufferedSource(source);
}
final class RealBufferedSource implements BufferedSource {
public final Buffer buffer = new Buffer();//內(nèi)部定義的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中讀入數(shù)據(jù)到內(nèi)部的Buffer中
if (read == -1) return -1;
}
long toRead = Math.min(byteCount, buffer.size);
return buffer.read(sink, toRead);//從內(nèi)部的buffer拷貝到sink目標(biāo)buffer
}
RealBufferedSource的做法,一樣是先通過一個Buffer來預(yù)取數(shù)據(jù),然后通過拷貝的方式拷貝到sink目標(biāo)緩存中。