Go package(3):io包介紹和使用


IO 操作的基本分類

在計算機中,處理文件和網絡通訊等,都需要進行 IO 操作,IO 即是 input/ouput,計算機的輸入輸出操作。

Go語言中的 IO 操作封裝在如下幾個包中:

當然除了上面這些,還有一些比如 json,xml,tar 等也屬於文件操作。

其中 io 包中的 io.Readerio.Writer 比較關鍵。io.Reader 接口實現了對文件、套接字等輸入設備的抽象;io.Writer 接口則實現了對輸出設備的抽象。

io 包提供了很多功能,這個包可以以流式的方式高效處理數據,而不用考慮數據是什么,數據來自哪里,以及數據要發送到哪里去。只要你實現了這2個接口。這就是抽象的能力。

IO包2個重要接口 Reader 和 Writer

在 io 包中有 2 個重要的接口:io.Readerio.Writer
實現了這2個接口,就可以使用 io 包的功能。

Reader 接口

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

Read() 方法將 len(p) 個字節讀取到 p 中。它返回讀取的字節數 n,以及發生錯誤時的錯誤信息。

  1. 如果讀到了數據(n > 0),則 err 應該返回 nil。
  2. 如果數據被讀空,沒有數據可讀(n == 0),則 err 應該返回 EOF。
  3. 如果遇到讀取錯誤,則 err 應該返回相應的錯誤信息。
  4. n 可能小於 len(p),也就是說在 Go 讀取 IO 時,是不會保證一次讀取預期的所有數據的。
  5. 如果要保證讀取所需的所有數據,就需要在一個循環里調用 Read,累加每次返回的數據。

只要某個實例實現了接口 io.Reader 里的方法 Read() ,就滿足了接口 io.Reader ,可以當做參數傳入進來。

io.EOF 變量的定義:var EOF = errors.New("EOF"),是 error 類型。根據 reader 接口的說明,在 n > 0 且數據被讀完了的情況下,當次返回的 error 有可能是 EOF 也有可能是 nil。

例子1: demo_reader.go 從標准輸入中讀取數據

package main

import (
	"fmt"
	"io"
	"os"
)

func ReadFrom(reader io.Reader, num int) ([]byte, error) {
	p := make([]byte, num)
	n, err := reader.Read(p)

	fmt.Println("n: ", n)

	if n > 0 {
		return p[:n], nil
	}
	return p, err
}

func main() {
	for {
		data, err := ReadFrom(os.Stdin, 4)
		if err != nil {
			if err == io.EOF {
				break
			}
		} else {
			fmt.Printf("receive: %X, %s\n", data, string(data))
		}
	}
}

Writer 接口

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

Write 方法將 len(p) 個字節從 p 中寫入到對象數據流中。它返回從 p 中被寫入的字節數 n,以及發生錯誤時返回的錯誤信息。

  1. 如果 p 中的數據全部被寫入,則 err 應該返回 nil。
  2. 如果 p 中的數據無法被全部寫入,則 err 應該返回相應的錯誤信息。

例子1 :demo_writer.go

package main

import (
	"bytes"
	"fmt"
	"os"
)

func main() {
	// 創建 Buffer 暫存空間,並將一個字符串寫入 Buffer
	// 使用 io.Writer 的 Write 方法寫入
	var buf bytes.Buffer
	buf.Write([]byte("hello world , "))

	// 用 Fprintf 將一個字符串拼接到 Buffer 里
	fmt.Fprintf(&buf, " welcome to golang !")

	// 將 Buffer 的內容輸出到標准輸出設備
	buf.WriteTo(os.Stdout)
}

bytes.Buffer 結構體:
bytes.Buffer 是一個結構體類型,用來暫存寫入的數據,這個結構體實現了 io.Writer 接口的 Write 方法。

Fprintf 方法定義:

func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)

第一個參數是 io.Writer 接口類型,bytes.Buffer 結構體實現了 io.Writer 接口里的 Write 方法,實現了 Write 方法的類型都可以作為參數(這里是 buf)傳入。

WriteTo 方法定義:

func (b *Buffer) WriteTo(w io.Writer) (n int64, err error)

WriteTo 方法第一個參數是 io.Writer 接口類型。

例子1:file_write.go

package main

import (
	"fmt"
	"os"
)

func main() {
	strings := []string{
		"hello, golang! \n",
		"welcome to golang! \n",
		"Go is a good lang. ",
	}

	file, err := os.Create("./writefile.txt")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	defer file.Close()

	for _, p := range strings {
		// file 類型實現了 io.Writer
		n, err := file.Write([]byte(p))
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		if n != len(p) {
			fmt.Println("failed to write data")
			os.Exit(1)
		}
	}

	fmt.Println("file wirte done")
}

把 strings 這個 slice 結構中的字符串寫入到名為 writefile.txt 的文件中。

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM