golang中bufio包的實現原理

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

最近用golang寫了一個處理檔案的指令碼,由於其中涉及到了檔案讀寫,開始使用golang中的 io 包,後來發現golang 中提供了一個bufio的包,使用這個包可以大幅提高檔案讀寫的效率,於是在網上搜尋同樣的檔案讀寫為什麼bufio 要比io的讀寫更快速呢?根據網上的資料和閱讀源碼,以下來詳細解釋下bufio的高效如何?的。

bufio 包介紹  

bufio包實現了有緩衝的I/O。它封裝一個io.Reader或io.Writer介面對象,建立另一個也實現了該介面,且同時還提供了緩衝和一些文本I/O的協助函數的對象。

以上為官方包的介紹,在其中我們能瞭解到的資訊如下:

  • bufio 是通過緩衝來提高效率

    簡單的說就是,把檔案讀取進緩衝(記憶體)之後再讀取的時候就可以避免檔案系統的io 從而提高速度。同理,在進行寫操作時,先把檔案寫入緩衝(記憶體),然後由緩衝寫入檔案系統。看完以上解釋有人可能會表示困惑了,直接把 內容->檔案 和 內容->緩衝->檔案相比, 緩衝區好像沒有起到作用嘛。其實緩衝區的設計是為了儲存多次的寫入,最後一口氣把緩衝區內容寫入檔案。下面會詳細解釋

  • bufio 封裝了io.Reader或io.Writer介面對象,並建立另一個也實現了該介面的對象

    io.Reader或io.Writer 介面實現read() 和 write() 方法,對於實現這個介面的對象都是可以使用這兩個方法的

bufio 包實現原理

bufio 源碼分析

  • Reader對象

    bufio.Reader 是bufio中對io.Reader 的封裝

    // Reader implements buffering for an io.Reader object.type Reader struct {    buf          []byte    rd           io.Reader // reader provided by the client    r, w         int       // buf read and write positions    err          error    lastByte     int    lastRuneSize int}

    bufio.Read(p []byte) 相當於讀取大小len(p)的內容,思路如下:

    1. 當緩衝區有內容的時,將緩衝區內容全部填入p並清空緩衝區
    2. 當緩衝區沒有內容的時候且len(p)>len(buf),即要讀取的內容比緩衝區還要大,直接去檔案讀取即可
    3. 當緩衝區沒有內容的時候且len(p)<len(buf),即要讀取的內容比緩衝區小,緩衝區從檔案讀取內容充滿緩衝區,並將p填滿(此時緩衝區有剩餘內容)
    4. 以後再次讀取時緩衝區有內容,將緩衝區內容全部填入p並清空緩衝區(此時和情況1一樣)

    以下是源碼

    // Read reads data into p.// It returns the number of bytes read into p.// The bytes are taken from at most one Read on the underlying Reader,// hence n may be less than len(p).// At EOF, the count will be zero and err will be io.EOF.func (b *Reader) Read(p []byte) (n int, err error) {    n = len(p)    if n == 0 {        return 0, b.readErr()    }    if b.r == b.w {        if b.err != nil {            return 0, b.readErr()        }        if len(p) >= len(b.buf) {            // Large read, empty buffer.            // Read directly into p to avoid copy.            n, b.err = b.rd.Read(p)            if n < 0 {                panic(errNegativeRead)            }            if n > 0 {                b.lastByte = int(p[n-1])                b.lastRuneSize = -1            }            return n, b.readErr()        }        // One read.        // Do not use b.fill, which will loop.        b.r = 0        b.w = 0        n, b.err = b.rd.Read(b.buf)        if n < 0 {            panic(errNegativeRead)        }        if n == 0 {            return 0, b.readErr()        }        b.w += n    }    // copy as much as we can    n = copy(p, b.buf[b.r:b.w])    b.r += n    b.lastByte = int(b.buf[b.r-1])    b.lastRuneSize = -1    return n, nil}

    說明:

    1. reader內部通過維護一個r, w 即讀入和寫入的位置索引來判斷是否緩衝區內容被全部讀出
  • Writer對象

    bufio.Writer 是bufio中對io.Writer 的封裝

    // Writer implements buffering for an io.Writer object.type Writer struct {    err error    buf []byte    n   int    wr  io.Writer}

    bufio.Write(p []byte) 的思路如下

    1. 判斷buf中可用容量是否可以放下 p
    2. 如果能放下,直接把p拼接到buf後面,即把內容放到緩衝區
    3. 如果緩衝區的可用容量不足以放下,且此時緩衝區是空的,直接把p寫入檔案即可
    4. 如果緩衝區的可用容量不足以放下,且此時緩衝區有內容,則用p把緩衝區填滿,把緩衝區所有內容寫入檔案,並清空緩衝區
    5. 判斷p的剩餘內容大小能否放到緩衝區,如果能放下(此時和步驟1情況一樣)則把內容放到緩衝區
    6. 如果p的剩餘內容依舊大於緩衝區,(注意此時緩衝區是空的,情況和步驟2一樣)則把p的剩餘內容直接寫入檔案

    以下是源碼

    // Write writes the contents of p into the buffer.// It returns the number of bytes written.// If nn < len(p), it also returns an error explaining// why the write is short.func (b *Writer) Write(p []byte) (nn int, err error) {    for len(p) > b.Available() && b.err == nil {        var n int        if b.Buffered() == 0 {            // Large write, empty buffer.            // Write directly from p to avoid copy.            n, b.err = b.wr.Write(p)        } else {            n = copy(b.buf[b.n:], p)            b.n += n            b.flush()        }        nn += n        p = p[n:]    }    if b.err != nil {        return nn, b.err    }    n := copy(b.buf[b.n:], p)    b.n += n    nn += n    return nn, nil}

    說明:

    1. b.wr 儲存的是一個io.writer對象,實現了Write()的介面,所以可以使用b.wr.Write(p) 將p的內容寫入檔案

    2. b.flush() 會將緩衝區內容寫入檔案,當所有寫入完成後,因為緩衝區會儲存內容,所以需要手動flush()到檔案

    3. b.Available() 為buf可用容量,等於len(buf) - n

    4. 解釋的是其中一種情況,即緩衝區有內容,剩餘p大於緩衝區

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.