在計算機和信息技術領域裏I/O
這個術語表示輸入 / 輸出 ( 英語:Input / Output ) ,一般指數據在存儲器(內部和外部)或其餘周邊設備之間的輸入和輸出,是信息處理系統與外部之間的通訊。輸入是系統接收的信號或數據,輸出則是從其發送的信號或數據。緩存
在Go語言中涉及I/O
操做的內置庫有不少種,好比:io
庫,os
庫,ioutil
庫,bufio
庫,bytes
庫,strings
庫等等。 擁有這麼多內置庫是好事,可是具體到涉及I/O
的場景咱們應該選擇哪一個庫呢?微信
Go語言裏使用io.Reader
和io.Writer
兩個 interface 來抽象I/O
,他們的定義以下。markdown
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
複製代碼
io.Reader
接口表明一個能夠從中讀取字節流的實體,而io.Writer
則掉吧一個能夠向其寫入字節流的實體。網絡
除了這幾種實現外經常使用的還有ioutil
工具庫包含了不少IO工具函數,編碼相關的內置庫encoding/base64
、encoding/binary
等也是經過 io.Reader 和 io.Writer 實現各自的編碼功能的。函數
這些經常使用實現和工具庫與io.Reader和io.Writer間的關係能夠用下圖表示。工具
io
庫屬於底層接口定義庫。它的做用主要是定義個I/O
的基本接口和個基本常量,並解釋這些接口的功能。在實際編寫代碼作I/O
操做時,這個庫通常只用來調用它的常量和接口定義,好比用io.EOF
判斷是否已經讀取完,用io.Reader
作變量的類型聲明。ui
// 字節流讀取完後,會返回io.EOF這個error
for {
n, err := r.Read(buf)
fmt.Println(n, err, buf[:n])
if err == io.EOF {
break
}
}
複製代碼
os
庫主要是處理操做系統操做的,它做爲Go程序和操做系統交互的橋樑。建立文件、打開或者關閉文件、Socket等等這些操做和都是和操做系統掛鉤的,因此都經過os
庫來執行。這個庫常常和ioutil
,bufio
等配合使用編碼
ioutil
庫是一個有工具包,它提供了不少實用的 IO 工具函數,例如 ReadAll、ReadFile、WriteFile、ReadDir。惟一須要注意的是它們都是一次性讀取和一次性寫入,因此使用時,尤爲是把數據從文件裏一次性讀到內存中時須要注意文件的大小。spa
讀出文件中的全部內容操作系統
func readByFile() {
data, err := ioutil.ReadFile( "./file/test.txt")
if err != nil {
log.Fatal("err:", err)
return
}
fmt.Println("data", string(data))
}
複製代碼
將數據一次性寫入文件
func writeFile() {
err := ioutil.WriteFile("./file/write_test.txt", []byte("hello world!"), 0644)
if err != nil {
panic(err)
return
}
}
複製代碼
bufio,能夠理解爲在io
庫的基礎上額外封裝加了一個緩存層,它提供了不少按行進行讀寫的函數,從io庫的按字節讀寫變爲按行讀寫對寫代碼來講仍是方便了很多。
func readBigFile(filePath string) error {
f, err := os.Open(filePath)
defer f.Close()
if err != nil {
log.Fatal(err)
return err
}
buf := bufio.NewReader(f)
count := 0
// 循環中打印前100行內容
for {
count += 1
line, err := buf.ReadString('\n')
line = strings.TrimSpace(line)
if err != nil {
return err
}
fmt.Println("line", line)
if count > 100 {
break
}
}
return nil
}
複製代碼
bytes 和 strings 庫裏的 bytes.Reader 和string.Reader,它們都實現了io.Reader
接口,也都提供了NewReader方法用來從[]byte
或者string
類型的變量直接構建出相應的Reader實現。
r := strings.NewReader("abcde")
// 或者是 bytes.NewReader([]byte("abcde"))
buf := make([]byte, 4)
for {
n, err := r.Read(buf)
fmt.Println(n, err, buf[:n])
if err == io.EOF {
break
}
}
複製代碼
另外一個區別是bytes庫有Buffer的功能,而strings庫則沒有。
var buf bytes.Buffer
fmt.Fprintf(&buf, "Size: %d MB.", 85)
s := buf.String()) // s == "Size: 85 MB."
複製代碼
關於io.Reader
和io.Writer
接口,能夠簡單理解爲讀源和寫源。也就是說,只要實現了Reader
中的Read
方法,這個東西就能夠做爲讀源,裏面能夠包含數據,被咱們讀取。Writer
也是如此。
以上是我對Go語言裏作I/O
操做時常常會用到的Go語言內置庫在使用場景和每一個庫要解決的問題上的一些總結,但願能幫你們理清思路,做爲參考,在開發任務中須要時正確選擇合適的庫完成I/O
操做。若是文章中的敘述有錯誤,歡迎留言指正,也歡迎在留言中對文章內容進行探討和提出建議。
今天的文章就到這裏啦,若是喜歡個人文章就幫我點個贊吧,我會每週經過技術文章分享個人所學所見和第一手實踐經驗,感謝你的支持。微信搜索關注公衆號「網管叨bi叨」每週教會你一個進階知識。