Go IO && bufio

IO

  • IO包 是對數據流的操做。從哪裏來, 怎麼處理,再到哪裏去。

圖片來源 https://medium.com/learning-the-go-programming-language/streaming-io-in-go-d93507931185golang

  • IO包 對數據的讀寫 是經過接口的形式約定的。數據的來源或者去向多是 網絡,內存,文件。
type Reader interface {
     Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}
  • 應用層 只須要按照接口去調用接口 不用關心底層實現細節 很是方便
package main

import (
    "io"
    "net/http"
    "os"
    "strings"
)

type R struct {
    reader io.Reader
}

func NewReader(r io.Reader) *R {
    return &R{
        reader: r,
    }
}

func (r *R) Read(p []byte) (n int, err error) {
    if _, err = r.reader.Read(p); err != nil {
        return
    }
    return len(p), nil
}

func main() {
    netR, err := http.Get("https://www.bilibili.com/")
    if err != nil {
        panic(err)
    }
    defer netR.Body.Close()
    fileR, err := os.Open("/tmp/data.txt")
    if err != nil {
        panic(err)
    }
    //讀內存
    r1 := NewReader(strings.NewReader(""))
    b := make([]byte, 10*1024)
    if _, err := r1.Read(b); err != nil {
        panic(err)
    }
    //讀網絡
    r2 := NewReader(netR.Body)
    if _, err := r2.Read(b); err != nil {
        panic(err)
    }
    //讀文件
    r3 := NewReader(fileR)
    if _, err := r3.Read(b); err != nil {
        panic(err)
    }
}

bufio

  • 每次對磁盤的寫入或者發起網絡請求 都會給系統帶來壓力。
    將屢次操做合併爲一次 會減輕系統的壓力
  • 更優的流程是 producer --> buffer -->io.Writer

參考:https://medium.com/golangspec/introduction-to-bufio-package-in-golang-ad7d1877f762緩存

func buffer() {
    fmt.Println("IO")
    w := new(W)
    w.Write([]byte{'1'})
    w.Write([]byte{'2'})
    w.Write([]byte{'3'})
    w.Write([]byte{'4'})

    fmt.Println("Buffer IO")
    bw := bufio.NewWriterSize(w, 3)
    bw.Write([]byte{'1'})
    bw.Write([]byte{'2'})
    bw.Write([]byte{'3'})
    bw.Write([]byte{'4'})
    err := bw.Flush()
    if err != nil {
        panic(err)
    }
}

type W struct {
}

func (*W) Write(p []byte) (n int, err error) {
    fmt.Println("length is ", len(p))
    fmt.Println(string(p))
    return len(p), nil
}
  • 普通的IO操做 會直接輸出
  • buffio 則會首先收集數據到緩存中 等判斷buffer滿了
    以後纔會一次性將緩存中的數據 輸出。緩存中可能有多餘的數據
    因此須要 最後單獨調用flush 函數 強制將未滿的緩存 輸出

ReadFrom

  • 寫操做以前須要 讀取數據。io.ReaderFrom interface 就是
    爲了更加方便的 從一個reader中讀取數據
type ReaderFrom interface {
        ReadFrom(r Reader) (n int64, err error)
}
func ReadFrom() {
    sr := strings.NewReader("read from strings reader")
    w := new(W)
    bw := bufio.NewWriterSize(w, 6)
    if _, err := bw.ReadFrom(sr); err != nil {
        panic(err)
    }
    if err := bw.Flush(); err != nil {
        panic(err)
    }
}
  • bufio.Writer實現了這個接口 從reader中讀取數據 io.reader -> buffer -> io.writer

ReadSlice

  • 若是bufio的NewReaderSize 若是小於16個字符 會設置爲默認長度16個字符
  • 讀取過程當中 會優先判斷buffer的size是否足夠大 不夠的話就會拋出 bufio: buffer full錯誤
  • bufio的ReadSlice函數能夠讀取讀取指定字符以前的字符串,若是讀到字符串末尾,尚未找到指定字符串
    則會返回eof
s := strings.NewReader("abc|defg\nhij")
    r := bufio.NewReader(s)
    b, err := r.ReadSlice('|')
    if err != nil {
        panic(err)
    }
    fmt.Println(string(b))

    b, err = r.ReadSlice('\n')
    if err != nil {
        panic(err)
    }
    fmt.Println(string(b))
相關文章
相關標籤/搜索