1. 程式人生 > 其它 >標準庫之input&output

標準庫之input&output

1、基本的io介面

  在 io 包中最重要的是兩個介面:Reader 和 Writer 介面。

  1.1Reader介面

Reader 介面的定義如下:

type Reader interface {
    Read(p []byte) (n int, err error)
}

Read 將 len(p) 個位元組讀取到 p 中。它返回讀取的位元組數 n(0 <= n <= len(p)) 以及任何遇到的錯誤。即使 Read 返回的 n < len(p),它也會在呼叫過程中佔用 len(p) 個位元組作為暫存空間。若可讀取的資料不到 len(p) 個位元組,Read 會返回可用資料,而不是等待更多資料。

當 Read 在成功讀取 n > 0 個位元組後遇到一個錯誤或 EOF (end-of-file),它會返回讀取的位元組數。它可能會同時在本次的呼叫中返回一個non-nil錯誤,或在下一次的呼叫中返回這個錯誤(且 n 為 0)。 一般情況下, Reader會返回一個非0位元組數n, 若 n = len(p) 個位元組從輸入源的結尾處由 Read 返回,Read可能返回 err == EOF 或者 err == nil。並且之後的 Read() 都應該返回 (n:0, err:EOF)。

呼叫者在考慮錯誤之前應當首先處理返回的資料。這樣做可以正確地處理在讀取一些位元組後產生的 I/O 錯誤,同時允許EOF的出現。

場景舉例:

func ReadFrom(reader io.Reader, num int) ([]byte, error) {
    p := make([]byte, num)
    n, err := reader.Read(p)
    if n > 0 {
        return p[:n], nil
    }
    return p, err
}

main(){
    // 從標準輸入讀取
    data, err = ReadFrom(os.Stdin, 11)

    // 從普通檔案讀取,其中 file 是 os.File 的例項
    data, err = ReadFrom(file, 9)

    // 從字串讀取
    data, err = ReadFrom(strings.NewReader("from string"), 12)
}

1.2Writer介面

Writer 介面的定義如下:

type Writer interface {
    Write(p []byte) (n int, err error)
}

Write 將 len(p) 個位元組從 p 中寫入到基本資料流中。它返回從 p 中被寫入的位元組數 n(0 <= n <= len(p))以及任何遇到的引起寫入提前停止的錯誤。若 Write 返回的 n < len(p),它就必須返回一個 非nil 的錯誤。

場景舉例:

//在使用 Go 語言進行 Web 開發時,http.ResponseWriter 是最基本的型別之一,它本身是一個 Interface 類,原型如下:
type ResponseWriter interface { Header() Header Write([]byte) (int, error) WriteHeader(int) }
//直接呼叫 Write() 寫入一串 []byte func helloHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") w.Write([]byte("Hello World")) return } func main() { http.HandleFunc("/", helloHandler) http.ListenAndServe(":8080", nil) }

1.3實現了 io.Reader 介面或 io.Writer 介面的型別

圍繞io.Reader/Writer,有幾個常用的實現:

  • net.Conn, os.Stdin, os.File: 網路、標準輸入輸出、檔案的流讀取
  • strings.Reader: 把字串抽象成Reader
  • bytes.Reader: 把[]byte抽象成Reader
  • bytes.Buffer: 把[]byte抽象成Reader和Writer
  • bufio.Reader/Writer: 抽象成帶緩衝的流讀取(比如按行讀寫)

2、ReaderAt 和 WriterAt 介面

2.1ReaderAt 介面

ReaderAt 介面的定義如下:
type ReaderAt interface {
    ReadAt(p []byte, off int64) (n int, err error)
}

ReadAt 從基本輸入源的偏移量 off 處開始,將 len(p) 個位元組讀取到 p 中。它返回讀取的位元組數 n(0 <= n <= len(p))以及任何遇到的錯誤。

當 ReadAt 返回的 n < len(p) 時,它就會返回一個 非nil 的錯誤來解釋 為什麼沒有返回更多的位元組。在這一點上,ReadAt 比 Read 更嚴格。

即使 ReadAt 返回的 n < len(p),它也會在呼叫過程中使用 p 的全部作為暫存空間。若可讀取的資料不到 len(p) 位元組,ReadAt 就會阻塞,直到所有資料都可用或一個錯誤發生。 在這一點上 ReadAt 不同於 Read。

若 n = len(p) 個位元組從輸入源的結尾處由 ReadAt 返回,Read可能返回 err == EOF 或者 err == nil

若 ReadAt 攜帶一個偏移量從輸入源讀取,ReadAt 應當既不影響偏移量也不被它所影響。

可對相同的輸入源並行執行 ReadAt 呼叫。

場景舉例:

reader := strings.NewReader("Go語言中文網")
p := make([]byte, 6)
n, err := reader.ReadAt(p, 2)
if err != nil {
    panic(err)
}
fmt.Printf("%s, %d\n", p, n)

2.2WriterAt 介面

WriterAt 介面的定義如下:
type WriterAt interface {
    WriteAt(p []byte, off int64) (n int, err error)
}

WriteAt 從 p 中將 len(p) 個位元組寫入到偏移量 off 處的基本資料流中。它返回從 p 中被寫入的位元組數 n(0 <= n <= len(p))以及任何遇到的引起寫入提前停止的錯誤。若 WriteAt 返回的 n < len(p),它就必須返回一個 非nil 的錯誤。

若 WriteAt 攜帶一個偏移量寫入到目標中,WriteAt 應當既不影響偏移量也不被它所影響。

若被寫區域沒有重疊,可對相同的目標並行執行 WriteAt 呼叫。

場景舉例:

file, err := os.Create("writeAt.txt")
if err != nil {
    panic(err)
}
defer file.Close()
file.WriteString("Golang中文社群——這裡是多餘")
n, err := file.WriteAt([]byte("Go語言中文網"), 24)
if err != nil {
    panic(err)
}
fmt.Println(n)

3、ReaderFrom 和 WriterTo 介面

3.1ReaderFrom 介面

ReaderFrom 的定義如下:

type ReaderFrom interface {
    ReadFrom(r Reader) (n int64, err error)
}

ReadFrom 從 r 中讀取資料,直到 EOF 或發生錯誤。其返回值 n 為讀取的位元組數。除 io.EOF 之外,在讀取過程中遇到的任何錯誤也將被返回。

如果 ReaderFrom 可用,Copy 函式就會使用它。

ReadFrom 方法不會返回 err == EOF。

場景舉例:

//將檔案中的資料全部讀取(顯示在標準輸出)
file, err := os.Open("writeAt.txt")
if err != nil {
    panic(err)
}
defer file.Close()
writer := bufio.NewWriter(os.Stdout)
writer.ReadFrom(file)
writer.Flush()
 

3.2WriterTo介面

WriterTo的定義如下:
type WriterTo interface {
    WriteTo(w Writer) (n int64, err error)
}

WriteTo 將資料寫入 w 中,直到沒有資料可寫或發生錯誤。其返回值 n 為寫入的位元組數。 在寫入過程中遇到的任何錯誤也將被返回。

如果 WriterTo 可用,Copy 函式就會使用它。

場景舉例:

//將一段文字輸出到標準輸出
reader := bytes.NewReader([]byte("Go語言中文網"))
reader.WriteTo(os.Stdout)

4、Seeker 介面

介面定義如下:

type Seeker interface {
    Seek(offset int64, whence int) (ret int64, err error)
}

  Seek 設定下一次 Read 或 Write 的偏移量為 offset,它的解釋取決於 whence: 0 表示相對於檔案的起始處,1 表示相對於當前的偏移,而 2 表示相對於其結尾處。 Seek 返回新的偏移量和一個錯誤,如果有的話。

場景舉例:

//獲取倒數第二個字元
reader := strings.NewReader("Go語言中文網")
reader.Seek(-6, io.SeekEnd)
r, _, _ := reader.ReadRune()
fmt.Printf("%c\n", r)

5、Closer介面

介面定義如下:
type Closer interface {
    Close() error
}

該介面比較簡單,只有一個 Close() 方法,用於關閉資料流。

檔案 (os.File)、歸檔(壓縮包)、資料庫連線、Socket 等需要手動關閉的資源都實現了 Closer 介面。

        參考1:io — 基本的 IO 介面 · Go語言標準庫 (studygolang.com) 參考2:Go程式設計技巧--io.Reader/Writer - 簡書 (jianshu.com)