Okio簡單分析

Okio的傳送門

https://github.com/square/okio


了解Okio之前先了解一個(gè)裝飾者模式(就是java io的思路)

  • 接下來簡單模擬一個(gè)io操作
  • 定義一個(gè)讀取數(shù)據(jù)的接口鸟廓,返回byte[ ]BytesReader
  • 定義一個(gè)它的實(shí)現(xiàn)類时捌,用來讀取byte[]挫鸽,BytesReaderImpl
  • 定義一個(gè)讀取String的接口粗卜,用來讀取StringReader
  • 對(duì)BytesReaderImpl進(jìn)行裝飾,,讓裝飾類支持讀取String贯底,StringReaderImpl
繼承關(guān)系圖
  • 看看具體的代碼實(shí)現(xiàn)吧 _( 比較簡單)
    ByteReader && ByteReaderImpl
 public interface BytesReader {
       byte[] readBytes(); //定義一個(gè)讀取byte[]的數(shù)組
 }

 public class BytesReaderImpl implements BytesReader {
   @Override
   public byte[] readBytes() {
       String str = "僅僅就是用來測(cè)試的字符串^_^...";
       return str.getBytes();
   }
}

StringReader && StringReaderImpl

  public interface StringReader extends BytesReader{
      String readString();
  }

  public class StringReaderImpl implements StringReader{
      private BytesReader bytesReader;
      public StringReaderImpl(BytesReader bytesReader) {
          this.bytesReader = bytesReader;
      }
      @Override
      public String readString() {
          byte[] bytes = bytesReader.readBytes();
          return new String(bytes);
      }
      @Override
      public byte[] readBytes() {
          return bytesReader.readBytes();
      }
  }

現(xiàn)在來看看okio的基本用法

public class Test {
    public static void main(String[] args){

       /* BytesReader bytesReader = new BytesReaderImpl();
        StringReader stringReader = new StringReaderImpl(bytesReader);

        System.out.println("readBytes  : "+bytesReader.readBytes().length);
        System.out.println("readString : "+stringReader.readString());*/

        File file = new File("D://demo.txt");
        File fileOut = new File("D://demo1.txt");
        BufferedSink sink = null;
        BufferedSource source = null;
        try {
            sink = Okio.buffer(Okio.sink(fileOut));
            source = Okio.buffer(Okio.source(file));
            byte[] buffer = new byte[12];
            int temp = 0;
            while((temp = source.read(buffer)) != -1){
                System.out.println("temp : "+temp);
                sink.write(buffer,0,temp);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(sink != null){
                    sink.close();
                }
                if(source != null){
                    source.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

}
  • okio里面有一個(gè),Source接口定義了讀取數(shù)據(jù)的接口撒强,類似InputStream
  • okio里面還有一個(gè)禽捆,Sink接口定義了寫數(shù)據(jù)的接口,類似OutputStream
  • Source和Sink有兩個(gè)實(shí)現(xiàn)類飘哨,BufferedSourceBufferedSink胚想,這兩個(gè)實(shí)現(xiàn)類定義了很多方法,包括文件的讀寫芽隆,字符串的讀寫浊服,流的讀寫 等
  • BufferedSource 和 BufferedSink有兩個(gè)之類,RealBufferedSource和RealBufferedSink**胚吁,實(shí)際用的時(shí)候其實(shí)是用的這兩個(gè)實(shí)現(xiàn)類
  • Okio這個(gè)類提供了很多靜態(tài)方法牙躺,簡化上面這些類的創(chuàng)建操作

下面開始分析源代碼

  • 首先有一點(diǎn)是明白的,就是Source和Sink這兩個(gè)類定義了頂層接口腕扶,一個(gè)用來讀數(shù)據(jù)孽拷,一個(gè)用來寫數(shù)據(jù)。
    Source && Sink

    public interface Source extends Closeable {
          long read(Buffer sink, long byteCount) throws IOException;
          Timeout timeout();
          @Override void close() throws IOException;
    }
    
      public interface Sink extends Closeable, Flushable {
          void write(Buffer source, long byteCount) throws IOException;
          @Override void flush() throws IOException;
          /** Returns the timeout for this sink. */
          Timeout timeout();
          @Override void close() throws IOException;
    }
    
  • Source和Sink分別有一個(gè)實(shí)現(xiàn)接口BufferedSource(接口)和BufferedSink(接口),這兩個(gè)接口就定義了更加偏向應(yīng)用的常用接口半抱,可以看到不管是讀還是寫都支持常見的類型脓恕,基本類型膜宋,String,而且Source接口和Sink接口接受的參數(shù)都是Buffer

      public interface BufferedSink extends Sink {
            Buffer buffer();
            BufferedSink write(ByteString byteString) throws IOException;
            BufferedSink write(byte[] source, int offset, int byteCount) throws IOException;
            BufferedSink writeUtf8(String string) throws IOException;
            BufferedSink writeShort(int s) throws IOException;
            .....
      }
    
      public interface BufferedSource extends Source {
             byte readByte() throws IOException;
             short readShort() throws IOException;
             short readShortLe() throws IOException;
             String readUtf8() throws IOException;
             .....
      }   
    
  • 可以看到不管是Source還是Sink接受的參數(shù)都是Buffer [okio.Buffer]炼幔,所以說Buffer在okio的讀寫種起著媒介(比較重要)的作用秋茫,Buffer的代碼有點(diǎn)多(1600+行)就提出一些比較重要的來說
  public final class Buffer implements BufferedSource, BufferedSink, Cloneable {
      Segment head;
      long size;

      @Override public OutputStream outputStream() {
              return new OutputStream() {
                        @Override public void write(int b) {
                            writeByte((byte) b);
                          }

                        @Override public void write(byte[] data, int offset, int byteCount) {
                                Buffer.this.write(data, offset, byteCount);
                          }
                        @Override public void flush(){}
                        @Override public void close() {}
                        @Override public String toString() {
                              return Buffer.this + ".outputStream()";
                         }
              };
        }  
        ...
        @Override public InputStream inputStream() {
                  return new InputStream() {
                        @Override public int read() {
                              if (size > 0) return readByte() & 0xff;
                              return -1;
                          }

                        @Override public int read(byte[] sink, int offset, int byteCount) {
                              return Buffer.this.read(sink, offset, byteCount);
                        }

                      @Override public int available() {
                              return (int) Math.min(size, Integer.MAX_VALUE);
                      }

                    @Override public void close() {
                      }

                    @Override public String toString() {
                            return Buffer.this + ".inputStream()";
                    }
            };
        }
        ....
  }
- 先簡單的說哈后面在回過來說,這里Buffer其實(shí)既有讀的功能也有寫的功能乃秀,但是我們的程序里面其實(shí)是可以像調(diào)用java io的api一樣肛著,因?yàn)槔锩姘b了一個(gè)OutputStream和InputStream ,這里還引入了一個(gè)新的對(duì)象环形,**Segment**
  • 有了大概的了解策泣,就來看看繼承圖


    okio部分類的繼承圖

繼續(xù)啊

  • 我們構(gòu)造BufferedSource是使用的是Okio.buffer(Okio.sink(fileOut));
    • 首先來看Okio.sink(fileOut),其實(shí)內(nèi)部就一句,return sink(new FileOutputStream(file));抬吟,構(gòu)造了一個(gè)FileOutputStream并調(diào)用了萨咕,sink(OutputStream out)方法,最終調(diào)用了sink(OutputStream out, Timeout timeout) 這個(gè)方法,其實(shí)就是構(gòu)造了一個(gè)Sink接口對(duì)象并返回。
        private static Sink sink(final OutputStream out, final Timeout timeout) {
      if (out == null) throw new IllegalArgumentException("out == null");
      if (timeout == null) throw new IllegalArgumentException("timeout == null");
    
      return new Sink() {
        @Override public void write(Buffer source, long byteCount) throws IOException {
          checkOffsetAndCount(source.size, 0, byteCount);
          while (byteCount > 0) {
            timeout.throwIfReached();
            Segment head = source.head;
            int toCopy = (int) Math.min(byteCount, head.limit - head.pos);
            out.write(head.data, head.pos, toCopy);
    
            head.pos += toCopy;
            byteCount -= toCopy;
            source.size -= toCopy;
    
            if (head.pos == head.limit) {
              source.head = head.pop();
              SegmentPool.recycle(head);
            }
          }
        }
    
        @Override public void flush() throws IOException {
          out.flush();
        }
    
        @Override public void close() throws IOException {
          out.close();
        }
    
        @Override public Timeout timeout() {
          return timeout;
        }
    
        @Override public String toString() {
          return "sink(" + out + ")";
        }
      };
    }
    
  • 上面的Sink返回了以后傳遞給了Okio.buffer方法火本,這個(gè)方法里面實(shí)際就是實(shí)例化了一個(gè)RealBufferedSink對(duì)象并返回危队。代碼就不貼了,說哈RealBufferedSink大概做了些什么钙畔,首先是RealBufferedSink里面包含了一個(gè)Buffer(可讀可寫)對(duì)象茫陆,在調(diào)用RealBufferedSink的時(shí)候,實(shí)際上就是調(diào)用的Buffer對(duì)象的write方法擎析。

  • BufferedSource和BufferedSink的處理是類似的這里就不啰嗦了簿盅。


小結(jié)前面提到的流程

  • 在構(gòu)造BufferedSource的時(shí)候會(huì)傳遞一個(gè)Source到Okio.buffer方法里面,而這個(gè)Source是一個(gè)匿名內(nèi)部類來實(shí)例化的揍魂,并且里面使用FileInputStream去讀取數(shù)據(jù)桨醋,然后吧數(shù)據(jù)保存到傳入的Buffer參數(shù)里面,而這個(gè)Buffer是支持讀寫的现斋。所以BufferedSource讀取Buffer里面的數(shù)據(jù)喜最,Buffer獲取從FileInputStream里面的數(shù)據(jù)。從這里就可以看出來庄蹋,Okio效率高就是這個(gè)Buffer在起作用瞬内,前面大概說了哈Buffer,它里面還有一個(gè)重要的對(duì)象還沒有說Segment

繼續(xù)哈

  • Segment對(duì)象限书,Segment的源碼不是很多虫蝶,實(shí)現(xiàn)的實(shí)現(xiàn)其實(shí)就是一個(gè)雙向鏈表。里面定義了一個(gè)byte[]和前一個(gè)節(jié)點(diǎn)的引用以及后一個(gè)節(jié)點(diǎn)的引用
final class Segment {
  /** The size of all segments in bytes. */
  static final int SIZE = 8192;
  /** Segments will be shared when doing so avoids {@code arraycopy()} of this many bytes. */
  static final int SHARE_MINIMUM = 1024;
  final byte[] data;
  int pos;
  int limit;
  boolean shared;
  boolean owner;
  Segment next;
  Segment prev;

  Segment() {
    this.data = new byte[SIZE];
    this.owner = true;
    this.shared = false;
  }
  ...
  public Segment pop() {
    Segment result = next != this ? next : null;
    prev.next = next;
    next.prev = prev;
    next = null;
    prev = null;
    return result;
  }

  public Segment push(Segment segment) {
    segment.prev = this;
    segment.next = next;
    next.prev = segment;
    next = segment;
    return segment;
  }
 ...
  public void writeTo(Segment sink, int byteCount) {
    if (!sink.owner) throw new IllegalArgumentException();
    if (sink.limit + byteCount > SIZE) {
      // We can't fit byteCount bytes at the sink's current position. Shift sink first.
      if (sink.shared) throw new IllegalArgumentException();
      if (sink.limit + byteCount - sink.pos > SIZE) throw new IllegalArgumentException();
      System.arraycopy(sink.data, sink.pos, sink.data, 0, sink.limit - sink.pos);
      sink.limit -= sink.pos;
      sink.pos = 0;
    }
    System.arraycopy(data, pos, sink.data, sink.limit, byteCount);
    sink.limit += byteCount;
    pos += byteCount;
  }
}
  • 現(xiàn)在可以來看看Buffer里面是怎么處理數(shù)據(jù)的了倦西,就挑一個(gè)read方法,其實(shí)就是直接將傳入的byte數(shù)據(jù)copy到了segment里面能真,這里又出來了一個(gè)新的類SegmentPool
@Override public int read(byte[] sink, int offset, int byteCount) {
   checkOffsetAndCount(sink.length, offset, byteCount);

   Segment s = head;
   if (s == null) return -1;
   int toCopy = Math.min(byteCount, s.limit - s.pos);
   System.arraycopy(s.data, s.pos, sink, offset, toCopy);

   s.pos += toCopy;
   size -= toCopy;

   if (s.pos == s.limit) {
     head = s.pop();
     SegmentPool.recycle(s);
   }

   return toCopy;
 }
  • SegmentPool就是一個(gè)回收池~~,讀取和寫入不斷的回收利用,同一個(gè)byte[]多次利用舟陆。

最后貼一個(gè)okio的整個(gè)繼承圖吧

點(diǎn)擊查看大圖

Nothing is certain in this life. The only thing i know for sure is that. I love you and my life. That is the only thing i know. have a good day

:)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市耻矮,隨后出現(xiàn)的幾起案子秦躯,更是在濱河造成了極大的恐慌,老刑警劉巖裆装,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件踱承,死亡現(xiàn)場離奇詭異,居然都是意外死亡哨免,警方通過查閱死者的電腦和手機(jī)茎活,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來琢唾,“玉大人载荔,你說我怎么就攤上這事〔商遥” “怎么了懒熙?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長普办。 經(jīng)常有香客問我工扎,道長,這世上最難降的妖魔是什么衔蹲? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任肢娘,我火速辦了婚禮,結(jié)果婚禮上舆驶,老公的妹妹穿的比我還像新娘橱健。我一直安慰自己,他們只是感情好贞远,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布畴博。 她就那樣靜靜地躺著,像睡著了一般蓝仲。 火紅的嫁衣襯著肌膚如雪俱病。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天袱结,我揣著相機(jī)與錄音亮隙,去河邊找鬼。 笑死垢夹,一個(gè)胖子當(dāng)著我的面吹牛溢吻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼促王,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼犀盟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蝇狼,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤阅畴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后迅耘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贱枣,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年颤专,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纽哥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡栖秕,死狀恐怖春塌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情累魔,我是刑警寧澤摔笤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站垦写,受9級(jí)特大地震影響吕世,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜梯投,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一命辖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧分蓖,春花似錦尔艇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蒸甜,卻和暖如春棠耕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背柠新。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國打工窍荧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人恨憎。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓蕊退,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓤荔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 前言 Okio是一款輕量級(jí)IO框架输硝,由安卓大區(qū)最強(qiáng)王者Square公司打造塞栅,是著名網(wǎng)絡(luò)框架OkHttp的基石。Ok...
    開發(fā)者小王閱讀 14,181評(píng)論 5 50
  • 1.OkHttp源碼解析(一):OKHttp初階2 OkHttp源碼解析(二):OkHttp連接的"前戲"——HT...
    隔壁老李頭閱讀 10,745評(píng)論 24 42
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理腔丧,服務(wù)發(fā)現(xiàn),斷路器作烟,智...
    卡卡羅2017閱讀 134,651評(píng)論 18 139
  • square在開源社區(qū)的貢獻(xiàn)是卓越的愉粤,這里是square在Android領(lǐng)域貢獻(xiàn)的開源項(xiàng)目。 1. okio概念 ...
    王英豪閱讀 1,183評(píng)論 0 2
  • 現(xiàn)在經(jīng)衬昧茫回憶小時(shí)候衣厘,仿佛昨天剛下課,今天突然就穿越過來压恒。中間那段時(shí)間刷刷刷地飛過去影暴,曾經(jīng)以為很久遠(yuǎn)的事情突然就變得...
    木目木目閱讀 300評(píng)論 0 0