Go package(3):io包介紹和使用
IO 操作的基本分類
在計(jì)算機(jī)中,處理文件和網(wǎng)絡(luò)通訊等,都需要進(jìn)行 IO 操作,IO 即是 input/ouput,計(jì)算機(jī)的輸入輸出操作。
Go語言中的 IO 操作封裝在如下幾個包中:
- io 為 IO 原語提供基本的接口
- io/ioutil 封裝一些實(shí)用的 I/O 函數(shù)
- fmt 實(shí)現(xiàn)了 I/O 的格式化
- bufio 實(shí)現(xiàn)了帶緩沖的 I/O
- net.Conn 網(wǎng)絡(luò)的讀寫
- os.Stdin, Stdout 系統(tǒng)標(biāo)準(zhǔn)輸入輸出
- os.File 系統(tǒng)文件操作
當(dāng)然除了上面這些,還有一些比如 json,xml,tar 等也屬于文件操作。
其中 io 包中的 io.Reader 和 io.Writer 比較關(guān)鍵。io.Reader 接口實(shí)現(xiàn)了對文件、套接字等輸入設(shè)備的抽象;io.Writer 接口則實(shí)現(xiàn)了對輸出設(shè)備的抽象。
io 包提供了很多功能,這個包可以以流式的方式高效處理數(shù)據(jù),而不用考慮數(shù)據(jù)是什么,數(shù)據(jù)來自哪里,以及數(shù)據(jù)要發(fā)送到哪里去。只要你實(shí)現(xiàn)了這2個接口。這就是抽象的能力。
IO包2個重要接口 Reader 和 Writer
在 io 包中有 2 個重要的接口:io.Reader和 io.Writer。
實(shí)現(xiàn)了這2個接口,就可以使用 io 包的功能。
Reader 接口
type Reader interface {
Read(p []byte) (n int, err error)
}
Read() 方法將 len(p) 個字節(jié)讀取到 p 中。它返回讀取的字節(jié)數(shù) n,以及發(fā)生錯誤時的錯誤信息。
- 如果讀到了數(shù)據(jù)(n > 0),則 err 應(yīng)該返回 nil。
- 如果數(shù)據(jù)被讀空,沒有數(shù)據(jù)可讀(n == 0),則 err 應(yīng)該返回 EOF。
- 如果遇到讀取錯誤,則 err 應(yīng)該返回相應(yīng)的錯誤信息。
- n 可能小于 len(p),也就是說在 Go 讀取 IO 時,是不會保證一次讀取預(yù)期的所有數(shù)據(jù)的。
- 如果要保證讀取所需的所有數(shù)據(jù),就需要在一個循環(huán)里調(diào)用 Read,累加每次返回的數(shù)據(jù)。
只要某個實(shí)例實(shí)現(xiàn)了接口 io.Reader 里的方法 Read() ,就滿足了接口 io.Reader ,可以當(dāng)做參數(shù)傳入進(jìn)來。
io.EOF 變量的定義:var EOF = errors.New("EOF"),是 error 類型。根據(jù) reader 接口的說明,在 n > 0 且數(shù)據(jù)被讀完了的情況下,當(dāng)次返回的 error 有可能是 EOF 也有可能是 nil。
例子1: demo_reader.go 從標(biāo)準(zhǔn)輸入中讀取數(shù)據(jù)
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) 個字節(jié)從 p 中寫入到對象數(shù)據(jù)流中。它返回從 p 中被寫入的字節(jié)數(shù) n,以及發(fā)生錯誤時返回的錯誤信息。
- 如果 p 中的數(shù)據(jù)全部被寫入,則 err 應(yīng)該返回 nil。
- 如果 p 中的數(shù)據(jù)無法被全部寫入,則 err 應(yīng)該返回相應(yīng)的錯誤信息。
例子1 :demo_writer.go
package main
import (
"bytes"
"fmt"
"os"
)
func main() {
// 創(chuàng)建 Buffer 暫存空間,并將一個字符串寫入 Buffer
// 使用 io.Writer 的 Write 方法寫入
var buf bytes.Buffer
buf.Write([]byte("hello world , "))
// 用 Fprintf 將一個字符串拼接到 Buffer 里
fmt.Fprintf(&buf, " welcome to golang !")
// 將 Buffer 的內(nèi)容輸出到標(biāo)準(zhǔn)輸出設(shè)備
buf.WriteTo(os.Stdout)
}
bytes.Buffer 結(jié)構(gòu)體:
bytes.Buffer 是一個結(jié)構(gòu)體類型,用來暫存寫入的數(shù)據(jù),這個結(jié)構(gòu)體實(shí)現(xiàn)了 io.Writer 接口的 Write 方法。
Fprintf 方法定義:
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
第一個參數(shù)是 io.Writer 接口類型,bytes.Buffer 結(jié)構(gòu)體實(shí)現(xiàn)了 io.Writer 接口里的 Write 方法,實(shí)現(xiàn)了 Write 方法的類型都可以作為參數(shù)(這里是 buf)傳入。
WriteTo 方法定義:
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error)
WriteTo 方法第一個參數(shù)是 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 類型實(shí)現(xiàn)了 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 結(jié)構(gòu)中的字符串寫入到名為 writefile.txt 的文件中。

浙公網(wǎng)安備 33010602011771號