Okio深入分析——基礎使用部分
一、前言
ofollow,noindex">Okio 的分析是為分析OkHttp打基礎的,當然,其實不瞭解也沒有關係,但是對於知識的體系化總會覺得像是缺了點什麼。而且相較於Java原的IO而言,其包含了非常多的特性,使得其在效能 以使用上非常的出色和容易。面對如此短小精悍的優秀程式碼,還有什麼理由拒絕學習它呢?這篇文章先來了解一下其具備的特性以及基礎的一些用法。
二、基本特性
1.基本特性
(1) 緊湊的封裝 是對Java IO/NIO 的一個非常優秀的封裝,絕對的“短小精焊”,不僅支援檔案讀寫,也支援Socket通訊的讀寫。
(2) 使用簡單 不用區分字元流或者位元組流,也不用記住各種不同的輸入/輸出流,統統只有一個輸入流Source和一個輸出流Sink。
(3) API豐富 其封裝了大量的API介面用於讀/寫位元組或者一行文字
(4) 讀寫速度快 這得益於其優秀的緩衝機制和處理記憶體的技巧,使I/O在緩衝區得到更高的複用處理,從而儘量減少I/O的實際發生。
2.支撐機制
與這些特性相比,就是其有強大的保障機制保駕護航
(1) 超時機制 在讀/寫時增加了超時機制,且有同步與非同步之分。
(2) 緩衝機制 讀/寫都是基於緩衝來來實現,儘量減少實際的I/O。
(3) 壓縮機制 寫資料時,會對緩衝的每個Segment進行壓縮,避免空間的浪費。當然,這是其內部的優化技巧,提高記憶體利用率。
(4) 共享機制 主要是針對 Segment 而言的,對於不同的 buffer 可以共享同一個 Segment。這也是其內部的優化技巧。
3.兩個核心基礎類
然而,在正式分析之前有兩個核心基礎類 ByteString 和 Buffer 和兩個核心API類需要提前理解一下,因為大量的API都是以這4個類為基礎來實現的。瞭解它們,以便有助於後面的分析。
ByteString是一個不可變的位元組序列。對於字元資料,String是基礎,ByteString則是String失散多年的好兄弟。其可以很容易地將二進位制資料視為一個值來處理。如用十六進位制,base64,和UTF-8來進行編碼和解碼。
Buffer是一個可變的位元組序列。就像ArrayList一樣,可以進行靈活的訪問,插入與移除,完全不需要自己去動手管理。
這兩個類也是上面機制的實現,正是上面機制的實現,才使得該庫以最少的實際IO來實現快速的IO需求。
三、基本使用
主要以官方demo加上自己的理解和知識來進行講解
1.讀取文字
public void readLines(File file) throws IOException { // 1.構建 Source try (Source fileSource = Okio.source(file); // 2.構建 BufferedSource BufferedSource bufferedSource = Okio.buffer(fileSource)) { while (true) { // 3.按 utf8 的格式逐行讀取字元 String line = bufferedSource.readUtf8Line(); if (line == null) break; if (line.contains("square")) { System.out.println(line); } } } }
這是一段按行讀取文字的程式碼,其首先構建一個Source,類似於Java的InputStream,然後構建一個BufferedSource,類似於Java的BufferedInputStream,最後就可以直接按行讀取文字了。看起來是不是很簡單呢。在對讀取有了一定的認識後,再深入看看Okio都提供了哪些讀取的API。先一個讀取相關的類圖。

Source.jpg
從使用者的角度來看,我們所需要了解的就是Source以及BufferedSource這兩個介面即可,具體的實現在RealBufferedSource,真的就這麼多了,是不是很簡單。
而在BufferedSource中可以看到,其封裝了大量的API,足夠滿足我們絕大部分的需求了,功能是不是很強大。
每次的讀取是基於緩衝機制的,這就提高了讀取的速度。
Demo中舉例是讀取文字,但如果要按位元組方式讀取的話,就使用BufferedSource#readByte()即可。或者如果檔案是自己定義的特殊結構,可以直接呼叫 readInt(),readLong() 等方法。
2.寫入文字
public void writeEnv(File file) throws IOException { // 1.構建 Sink try (Sink fileSink = Okio.sink(file); // 2.構建 BufferedSink BufferedSink bufferedSink = Okio.buffer(fileSink)) { // 3.寫入文字 for (Map.Entry<String, String> entry : System.getenv().entrySet()) { bufferedSink.writeUtf8(entry.getKey()); bufferedSink.writeUtf8("="); bufferedSink.writeUtf8(entry.getValue()); bufferedSink.writeUtf8("\n"); } } }
這段程式碼演示瞭如何寫入一個文字到檔案。其先構建一個Sink,類似於Java的OutputStream,再構建一個BufferedSink,類似於Java的 BufferedOutputStream。然後就可以寫入文字了。同樣,是不是很簡單呢。也先來看看寫入相關的類圖。

Sink.jpg
幾乎就是和讀取的類圖有著一一對應的API。對於開發者來說,瞭解上面的這些介面也就夠了,其豐富的寫入API也幾乎能滿足我們絕大部分的需求了。
四、總結
真的很簡單,以致於不知該總結什麼了,特性以及該說的都在上面說了。當然,知其然而不知其所以然,始終會讓人覺得不爽。下一篇再深入瞭解其具體的封裝和強大保障機制的實現。我們要知道它為什麼好,為什麼快。