08 | Android 高級進階(源碼剖析篇) Square 高效易用的 IO 框架 okio(一)

作者簡介:ASCE1885, 《Android 高級進階》作者。
本文由于潛在的商業(yè)目的,未經(jīng)授權(quán)不開放全文轉(zhuǎn)載許可,謝謝!
本文分析的源碼版本已經(jīng) fork 到我的 Github。

ab99a96150c02544a9585b45ac5fcd3b73b9363jpg.jpg

okio 是 Square 開源的一個 Java IO 框架,是對 java.iojava.nio 的補充,提供了更靈活易用的接口來處理數(shù)據(jù)流的輸入和輸出,最開始它是作為 okhttp 的一個基礎(chǔ)組件存在的,后面隨著 okhttp 的不斷發(fā)展逐漸剝離獨立出來。我們知道,okio 和 okhttp 并不只局限在 Android 平臺中使用,事實上,它們是 Java 平臺通用的,在 Java 后端開發(fā)中也經(jīng)常會用到,例如在著名的微服務(wù)框架 Spring Cloud 中,就可以通過配置使用 okhttp 來代替默認的 HttpClient,從而支持 HTTP/2。

IO 和 NIO

在正式介紹 okio 之前,我們有必要先來回顧一下 java.iojava.nio 的基礎(chǔ)知識。I/O(input/output) 是計算機與外部世界之間的接口,也是一個應用與外部系統(tǒng)的接口。在 Java 編程中,I/O 被形象的表述為流的概念。所有的 I/O 操作可以被看作是字節(jié)在流中的移動,一次一個字節(jié)。流中的 I/O 操作既可以用來與外部系統(tǒng)聯(lián)系,也可以用于內(nèi)部實現(xiàn)字節(jié)和對象或者對象和字節(jié)之間的轉(zhuǎn)換。

java.io(后面以 IO 代之) 和 java.nio(后面以 NIO 代之) 可以從以下三方面作一個對比:

IO 是基于數(shù)據(jù)流的,而 NIO 是基于數(shù)據(jù)塊的

IO 和 NIO 最重要的區(qū)別就是數(shù)據(jù)的打包和傳輸方式。IO 是在流中處理數(shù)據(jù),NIO 是在塊中處理數(shù)據(jù)。

基于流的 I/O 系統(tǒng)一次處理一個或者多個字節(jié),當輸入流生產(chǎn)一個字節(jié)信息,輸出流就消費一個字節(jié)的信息。我們可以很容易的為流數(shù)據(jù)創(chuàng)建過濾器,并通過把不同的過濾器串聯(lián)起來從而實現(xiàn)復雜的流處理機制。當然,在流中字節(jié)信息是沒有緩存的,因此你不能在流中來回的移動數(shù)據(jù)讀取的指針,除非你先把字節(jié)信息在某個地方緩存起來。

基于塊的 I/O 系統(tǒng)是在塊中處理數(shù)據(jù)的,每一次操作都會生產(chǎn)或者消費一塊數(shù)據(jù),基于塊比基于流的方式處理數(shù)據(jù)速度更快。你可以在緩沖區(qū)(Buffer)中來回移動數(shù)據(jù)讀取或者寫入指針,因此靈活性更強。但是我們在往緩沖區(qū)中寫入更多數(shù)據(jù)之前需要確保緩沖區(qū)中的數(shù)據(jù)能夠及時處理,從而不會造成數(shù)據(jù)的覆蓋。因此,基于塊的 I/O 系統(tǒng)相比基于流的 I/O 系統(tǒng)而言顯得不怎么優(yōu)雅和簡潔。

IO 是同步的,NIO 是異步的

IO 中各種各樣的流都是阻塞或者同步的,這意味著當一個線程調(diào)用流的 read() 或者 write() 方法時,在數(shù)據(jù)處理完之前該線程將始終處于阻塞的狀態(tài)。而 NIO 是支持異步的,也就是一個線程收到數(shù)據(jù)的讀或者寫請求后,可以將數(shù)據(jù)處理發(fā)送給通道(Channel),同時不必等待數(shù)據(jù)處理完成就可以返回來繼續(xù)處理其他請求。

API 的差異

為了讓大家有個直觀的印象,我們就來看看 IO 和 NIO 在讀取一個文件時的代碼,首先來看下 IO 是如何讀取文件的,這里因為是讀取一個 txt 文件,因此使用 Reader 類,其中 FileReader 底層是使用 InputStream 來讀取文件的:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class WithoutNIOExample {
    public static void main(String[] args) {
        BufferedReader br = null;
        String sCurrentLine = null;
        try {
            br = new BufferedReader(
                    new FileReader("test.txt"));
            while ((sCurrentLine = br.readLine()) != null) {
                System.out.println(sCurrentLine);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (br != null)
                    br.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
}

NIO 讀取文件時需要結(jié)合緩沖區(qū)(Buffer)和通道(Channel)一起使用,代碼如下所示:

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ReadFileWithFixedSizeBuffer {
    public static void main(String[] args) throws IOException {
        RandomAccessFile aFile = new RandomAccessFile
                ("test.txt", "r");
        FileChannel inChannel = aFile.getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while (inChannel.read(buffer) > 0) {
            buffer.flip();
            for (int i = 0; i < buffer.limit(); i++) {
                System.out.print((char) buffer.get());
            }
            buffer.clear();
        }
        inChannel.close();
        aFile.close();
    }
}

okio

okio 自身定義了一系列的概念,本文我們先來對其中四個核心的概念進行簡單的介紹。

還有 50% 的精彩內(nèi)容
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
支付 ¥5.20 繼續(xù)閱讀

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容