在 OkHttp 的原始碼中,我們經常能看到 Okio
的身影,這篇文章,我們把Okio
拿出來進行一個詳細的介紹學習。
在正式介紹 Okio 之前,讓我們先回憶一下輸入/輸出流
的概念。
輸入流:外設——>記憶體
輸出流:記憶體——>外設
Okio最初是作為OkHttp的一個元件
出現,是 OkHttp 實現HTTP協定資料構建、解析中使用到的底層 IO 庫。其相比於傳統的 java.io 和 java.nio ,其在檔案
、網路
等資料讀寫操作更加便捷、高效
。
Okio
的設計思想是將資料的讀寫
操作封裝為一個統一的介面,即 Source
和 Sink
,其中 輸入為Source,輸出為Sink 。
Okio
還提供了 Buffer
和 ByteString
用於封裝和操作位元組資料
,提高資料讀寫的效率。Okio
還提供了一些工具方法,例如從 InputStream
或 OutputStream
中建立 BufferedSource
、BufferedSink
等。Okio官方API地址為:
https://square.github.io/okio/
Okio Github開源地址為:
https://github.com/square/okio
使用 Okio 時,我們可以查閱官方最新版本,並通過如下方式引入Okio:
implementation("com.squareup.okio:okio:3.2.0")
Buffer
是一個大小可變的位元組緩衝區
,在Okio中Buffer
是BufferedSource
和BufferedSink
的介面實現類,使用者實現位元組資料的緩衝與讀寫。
官方API描述如下:
Buffer
可以像Arraylist
一樣,不需要預先設定緩衝區的大小,而是隨著資料的增加自動擴充緩衝區大小
。Buffer
由很多的Segment
片段構成,每個Segment
中維護一個位元組陣列
。Buffer
中以連結串列的形式來管理Segment
,當使用Buffer
進行緩衝區位元組資料移動時,其只改變Segment
位元組陣列的所有權,從而提高位元組陣列的移動效率。okio.Buffer
位元組緩衝區的使用方式舉例如下:
import okio.Buffer;
Buffer buffer = new Buffer();
// 向緩衝區寫入資料
buffer.writeUtf8("key");
buffer.writeByte('=');
buffer.writeUtf8("value");
// 緩衝區位元組大小
int byteCount = buffer.size();
// 讀取換區中的全部位元組資料
byte[] byteArray = buffer.readByteArray();
// 以Utf8編碼的形式輸出所有字串
String result = buffer.readUtf8();
// 清空緩衝區
buffer.clear();
ByteString
中維護了大小不可變的位元組陣列
,其可以對存入該位元組陣列的資料進行base64
、utf8
、md5
、sha256
等字串的編解碼操作。
ByteString
更像是一個工具類,在Okio
中其重要應用場景也是在網路傳輸中對資料進行編碼和解碼工作
。
官方API描述如下:
其部分靜態方法和公有方法如下圖所示:
okio.ByteString
的使用方式舉例如下:
import okio.ByteString;
// utf8編碼
ByteString byteString = ByteString.encodeUtf8("hello");
// HEX
ByteString byteString = ByteString.decodeHex("hello");
// 輸出utf8字串
String result = byteString.utf8();
Source 和 Sink 在前文中提到過輸入為Source,輸出為Sink。在 Okio 中,Source
和 Sink
用於讀取
和寫入
資料的抽象類
,其提供了一組標準的IO讀寫方法,可以方便地進行資料的讀寫操作。
// Okio原始碼:輸入流 Source
// Source 介面類,最主要的方法是 read
public interface Source extends Closeable {
// 讀位元組資料
long read(Buffer var1, long var2) throws IOException;
// timeout
Timeout timeout();
void close() throws IOException;
}
// Okio原始碼:輸出流 Sink
// Sink 介面類,最主要的方法是 write
public interface Sink extends Closeable, Flushable {
// 寫位元組資料
void write(Buffer var1, long var2) throws IOException;
void flush() throws IOException;
Timeout timeout();
void close() throws IOException;
}
在把前文已經展示過的Okio結構圖拿出來:
Source
的最終實現類是RealBufferedSource
;Sink
的最終實現類是RealBufferedSink
;使用 okio.Source
從檔案中讀取資料,程式碼舉例如下:
// 使用 Source 從檔案中讀取資料
public static void readLines(File file) throws IOException {
// 輸入流
Source fileSource = Okio.source(file);
// 構建 BufferedSource
RealBufferedSource bufferedSource = Okio.buffer(fileSource);
// 迴圈讀取
while (true) {
// 讀取行資料
String line = bufferedSource.readUtf8Line();
if (line == null) {
break;
}
}
}
使用 okio.Sink
向檔案中寫入資料,程式碼舉例如下:
// 使用 Sink 向檔案中寫入資料
public static void writeToFile(File file) throws IOException {
// 建立輸出流
Sink fileSink = Okio.sink(file);
// 構造 BufferedSink
RealBufferedSink bufferedSink = Okio.buffer(fileSink);
// 向檔案中寫入資料
bufferedSink.writeUtf8("Hello");
bufferedSink.writeUtf8("\n");
bufferedSink.writeAll(Okio.source(new File("my.txt")));
}
Okio API:
https://square.github.io/okio/
Okio Github:
https://github.com/square/okio
Java流:
http://c.biancheng.net/view/1119.html
文章首發於公眾號」CODING技術小館「,如果文章對您有幫助,歡迎關注我的公眾號。