Golang - 認識 io package 的原理與操作
在 Golang 中,輸入輸出的操作最先理解的是 io package,因為 io package 定義兩個 io.Reader 和 io.Writer 接口,分別用來抽象化輸入輸出的操作,因此認識 io package 是掌握 Go 中輸入輸出的基礎。
最近因為在工作上有用到 io 相關操作,因此來紀錄一下~
io.Reader 接口
查看原始碼可以發現,io.Reader 定義 Reader interface:
1 | type Reader interface { |
在接口裡面定義了 Read 行為,這個行為的意思是 Read 會將資料讀進 p,講白了就是緩衝區的意思,並傳回兩個參數,n 代表是讀取到的位元組數,通常在讀取的過程中回傳的 n 都會是 len§,也就是將數據丟到 p 裡面將其塞滿。而如果傳回的 n 不到 len (n),這代表下一次的讀取到了結尾,會將 err 改成 io.EOF 並回傳,以檔案來說的話就是檔案結尾的意思,因此在這之後 n 都會是 0 而 err 會是 io.EOF
在 io 包裡面有定義了有些於 io.EOF 的相關錯誤:
1 | // ErrShortWrite means that a write accepted fewer bytes than requested |
根據讀取的情況回傳相對應的 err,如果沒有發生錯誤就會回傳 nil。
來看個例子:
1 | func main() { |
透過 strings package 產生一個字串 Reader,該 Reader 有實現 Read 行為,在透過建立一個長度為 4 的 [] byte,透過 reader.Read§ 將字串讀進去 p 裡面。
來看輸出結果:
1 | 4 Codi |
可以看到前面都是每 4 個字元讀取,最後因為剩下兩個字元,並沒有將 p 塞滿,而在讀取的話就會回傳 io.EOF 的 err,為的就是告知已經讀取到結尾,回傳的 n 一定是 0。
io.Writer 接口
查看原始碼可以發現,io.Writer 定義 Writer interface:
1 | type Writer interface { |
裡面定義了 Write 行為,其意思代表會將 p 裡面的數據輸出,會回傳實際謝入的位元組數,n 同樣會是從 0 到不大於 len§ 的整數,通常回傳的 n 如果小於 len§,err 會回傳 io.ErrShortWrite,而不會是 nil。
來看例子:
1 | func main() { |
透過字串的 Reader,將字串讀進去 p,接著透過 os.Stdout 產生 Writer,該 os.Stdout 實際上就是 * File,有實現 Write 行為。
透過 writer.Write§,將讀進來的字串用成標準輸出,也就是會輸出在 console 上。
運行結果:
1 | Codi |
可以看出每次都是 Write p 長度的字串出來。最後當讀到結尾時,reader.Read 會回傳 io.EOF 的錯誤,因此就不需要 writer.Write 繼續輸出。
io.Copy () 介紹
io 套件裡面也實踐了 Copy (),提供功能就是可以將 Reader 裡面的數據 Copy 到另一個 Writer 上。
看個例子:
1 | func main() { |
透過 strings.NewReader 讀入字串,建立標準輸出的 writer,透過 Copy 的方式將其字串輸出。而 io.Copy 實際上的原始碼其實就是上面示範的 For 迴圈讀取寫入的包裝,並且幫我們處理 err 的問題。因此這個 n 回傳的是 Writer 總共寫入多少字元數,err 有可能會回傳非 io.EOF 的其他錯誤,裡面實現的方式已經幫我們處理 io.EOF 的錯誤,因此這邊 Copy 不會回傳 io.EOF。
io.WriteString () 介紹
這個函數能夠方便地將字串型態寫入一個 Writer 幫我們做輸出。
來看例子:
1 | func main() { |
輸出結果如下:
1 | Coding is interesting |
一樣回傳的 n 是寫入的字節數,這邊底層實現其實就是調用傳進去的 writer 其 write () 實現方法而已,因此會回傳的 err 如同前面。
總結
所有 io 操作,一定都是透過去實現 Reader、Writer 去組合而成的,Golang 中提供許多 IO 操作的標準庫,底層都是運用 io package 的行為。
例如有:bufio 套件、bytes 套件、os 套件的 File (裡面就包含 os.Stdout、os.Stdin、os.Stderr,分別代表標準輸入、標準輸出、標準錯誤)。
io package 裡面還有其他函式提供方便操作,這邊就不多講實際上去看文檔就可以了,主要就是要理解 Golang io 操作原理是源自於此 io 包。
最後最後!請聽我一言!
如果你還沒有註冊 Like Coin,你可以在文章最下方看到 Like 的按鈕,點下去後即可申請帳號,透過申請帳號後可以幫我的文章按下 Like,而 Like 最多可以點五次,而你不用付出任何一塊錢,就能給我寫這篇文章的最大的回饋!