如果看官從事Android開發(fā),相信你們對(duì)Okhttp這個(gè)框架并不陌生,當(dāng)然非墨以后也會(huì)解析它。今天我們所說的Okio這個(gè)庫,實(shí)際上是Java平臺(tái)上的一個(gè)IO裝飾庫,在Okhttp這個(gè)框架中實(shí)際上也引用了這個(gè)庫。本章先帶大家簡(jiǎn)單的入門,熟悉一個(gè)Okio的一些基本概念和設(shè)計(jì)原則。
[Okio github 地址:https://github.com/square/okio]
Okio在設(shè)計(jì)上非常簡(jiǎn)單,主要分成幾個(gè)大分支:
- Source :Okio重新定義了流的名稱,用Source代替InputStream,當(dāng)然,實(shí)際上底層還是用Jre的InputStream來做流操作,只不過在Okio中,對(duì)于輸入流的所有操作都包含在Source接口下。
2.Sink : Okio重新定義了流的名稱Sink用于替代OutputStream,當(dāng)然如同Source一樣,底層一樣用的OutputStream處理流操作。
3.Buffer:Buffer是Okio中的重頭類。之所以說重頭,并不是因?yàn)樗卸嗌俚拇a量,而是這個(gè)類承擔(dān)了很多有用且實(shí)際的功能。
4.Segment:是Buffer管理中的內(nèi)存單位,類似操作系統(tǒng)中的分頁式存儲(chǔ)。
5.其他子類:其他子類包含有Source和Sink的各種緩沖類和裝飾類。
這里我們將引入Okio中的demo代碼,大家可以到Okio的github地址里找到這段代碼。這段代碼主要是為了在程序中讀取一個(gè)png文件:
BufferedSource pngSource = Okio.buffer(Okio.source(in));
//構(gòu)建buffersource流
ByteString header = pngSource.readByteString(PNG_HEADER.size());
//獲取一個(gè)ByteString
if (!header.equals(PNG_HEADER)) {
throw new IOException("Not a PNG.");
}
while (true) {
Buffer chunk = new Buffer();
// Each chunk is a length, type, data, and CRC offset.
int length = pngSource.readInt();
String type = pngSource.readUtf8(4);
pngSource.readFully(chunk, length);
int crc = pngSource.readInt();
decodeChunk(type, chunk);
if (type.equals("IEND")) break;
}
pngSource.close();
我們可以看到:
1.在代碼的第一行,Okio將先通過一個(gè)source靜態(tài)方法來構(gòu)造一個(gè)Source對(duì)象。按照我們上面的理解,Source實(shí)際上就是一個(gè)輸入流,只不過這個(gè)輸入流就像是InputStream一樣,只提供一些最為基本的讀取操作。因此,為了讓我們的輸入流能實(shí)現(xiàn)更加豐富多彩的數(shù)據(jù)流格式,Okio需要在外面包裝一個(gè)BufferedSource接口。
2.代碼的第二行,實(shí)際上是通過BufferedSource來獲取一個(gè)長度
為"PNG_HEADER".size()的ByteString對(duì)象,這個(gè)操作主要是為了給這個(gè)文件做一個(gè)簡(jiǎn)單的類型判斷。在我們的字節(jié)碼文件也有一樣的驗(yàn)證部分,這一部分叫做文件"魔數(shù)"或者叫做"文件署名域"。
3.接下去,就是解析PNG文件的while(true)語句,基于while(true)的語法特性,我們基本可以斷定png文件的存儲(chǔ)是一種塊狀結(jié)構(gòu),我們不妨到百科上查一下PNG文件的格式是什么樣的,下圖是非墨摘自百度百科的png文件數(shù)據(jù)塊結(jié)構(gòu)圖:
PNG數(shù)據(jù)塊結(jié)構(gòu)
按照png文件塊的規(guī)范:
第一個(gè)u4長度的數(shù)據(jù)代表數(shù)據(jù)塊中的數(shù)據(jù)長度
第二個(gè)u4長度的數(shù)據(jù)代表數(shù)據(jù)塊類型
第三部分代表真實(shí)數(shù)據(jù)
第四部分u4長度的數(shù)據(jù)是CRC校驗(yàn)位
其中,第三部分的類型取值如下表:
PNG文件數(shù)據(jù)塊類型取值
根據(jù)上面的知識(shí)儲(chǔ)備,我們就很好理解在while(true)代碼塊中中代碼含義:
Buffer chunk = new Buffer();
// Each chunk is a length, type, data, and CRC offset.
int length = pngSource.readInt();//讀取數(shù)據(jù)塊長度
String type = pngSource.readUtf8(4);//讀取類型數(shù)據(jù)
pngSource.readFully(chunk, length);//讀取數(shù)據(jù)到chunk
int crc = pngSource.readInt();//讀取crc校驗(yàn)位
decodeChunk(type, chunk);
if (type.equals("IEND")) break;
我們可以看到,通過BufferedSource的轉(zhuǎn)換,我們可以獲取各式各樣的數(shù)據(jù)格式,比如Int,utf等等。它這個(gè)東西,非常類似于DataInputStream對(duì)象。就這樣,我們完成了一個(gè)Png文件的讀取。

