這篇文章是對區塊鏈開發中Go語言之IO操作做一個梳理,每一個的地方,每一種的知識,每一種事物,都是從陌生到熟悉。在這個過程里面,或許能開闊眼界,增長見識,體驗樂趣,下面我們就一起來看看吧。
type Reader interface { Read(p []byte) (n int, err error)}
實現了Reader接口的都可以用read方法,將數據讀入到p字節數組,n表示讀取了幾個字節,err返回錯誤。 如果讀到了文件尾EOF,則err返回EOF。
注意,當文件最后一小段已經無法填滿p這個字節數組時,不會產生EOF的錯誤,只會在下一次讀取時產生n=0,err=io.EOF的錯誤
舉例
func main() { file, _ := os.Open("main.go") var a [128]byte count:=0 for { n, err := file.Read(a[:]) count+=1 if err != nil { if err == io.EOF { break } else { os.Exit(1) } } fmt.Printf("%s/n", a[:n]) } fmt.Printf("%d/n", count)}
type Writer interface { Write(p []byte) (n int, err error)}
Write 將 len(p) 個字節從 p 中寫入到基本數據流中。它返回從 p 中被寫入的字節數 n(0 常見錯誤原因有磁盤滿了
和Reader,Writer類似,但是需要自己調控偏移量。
注意:接近文件尾巴時,當n小于數組大小時也觸發了err.EOF,需要自行把最后n小于數組大小的這點數據處理一下。
舉例:
func main() { file, _ := os.Open("main.go") var a [128]byte count := 0 var pos int64 = 0 for { n, err := file.ReadAt(a[:], pos) count += 1 pos += int64(n) if err != nil { if err == io.EOF { fmt.Printf("%s", a[:n]) //區別在這里 break } else { os.Exit(1) } } fmt.Printf("%s", a[:n]) } fmt.Println() fmt.Printf("%d", count)}
一次性讀完直到EOF,或者寫入全部數據
type Seeker interface { Seek(offset int64, whence int) (ret int64, err error)}
用來設置偏移量,也就是從哪開始讀,offset由whence解釋。
讀或寫一個字節
一次性讀取數據
讀取目錄并返回排好序的文件和子目錄名
func WriteFile(filename string, data []byte, perm os.FileMode) error
這里特別注意的是寫文件的權限問題,perm的數值,和linux規則一致 四位(777):
模式 | 數字 |
---|---|
rwx | 7 |
rw- | 6 |
r-x | 5 |
r-- | 4 |
-wx | 3 |
-w- | 2 |
--x | 1 |
--- | 0 |
組合如0666,表示rw-rw-rw- | ? |
是io庫的包裝,提供帶緩存的方法
后三個方法最終都是調用ReadSlice來實現的
func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
示例:
reader := bufio.NewReader(strings.NewReader("http://studygolang.com. /nIt is the home of gophers"))line, _ := reader.ReadSlice('/n')fmt.Printf("the line:%s/n", line)// 這里可以換上任意的 bufio 的 Read/Write 操作n, _ := reader.ReadSlice('/n')fmt.Printf("the line:%s/n", line)fmt.Println(string(n))
輸出:
the line:http://studygolang.com. the line:It is the home of gophersIt is the home of gophers
注意ReadSlice每次返回的line是指向同一個緩存數組,因此ReadSlice的實現是反復覆蓋重寫緩存數組。
如果ReadSlice在找到分界符前
func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
返回的byte是copy的一份數組
從以下實驗可看出來
reader := bufio.NewReader(strings.NewReader("http://studygolang.com. /nIt is the home of gophers"))line, _ := reader.ReadBytes('/n')fmt.Printf("the line:%s/n", line)// 這里可以換上任意的 bufio 的 Read/Write 操作n, _ := reader.ReadBytes('/n')fmt.Printf("the line:%s/n", line)fmt.Println(string(n))
輸出
the line:http://studygolang.com. the line:http://studygolang.com. It is the home of gophers
是對ReadBytes的封裝,將返回的line轉換成string
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
這里要說的是isPrefix,用于讀取的一行超過了緩存大小,則isPrefix為true,下次還讀這行余下的部分,直到讀完這行才isPrefix返回false
ReadLine返回的文本不會包含行結尾("/r/n"或者"/n")
該方法只是“窺探”一下Reader中沒有讀取的n個字節。好比棧數據結構中的取棧頂元素,但不出棧。
func (b *Reader) Peek(n int) ([]byte, error)
同上面介紹的ReadSlice一樣,返回的[]byte只是buffer中的引用。所以在并發的時候有可能就被別人給改了
用于方便的按token讀取數據,token的分詞規則用SplitFunc定義。默認按行分詞,會去掉末尾換行符。 了解Scanner前要先了解SplitFunc
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)
SplitFunc 定義了 用于對輸入進行分詞的 split 函數的簽名。
參數
返回值
舉例
func main() { // Comma-separated list; last entry is empty. const input = "1,2,3,4," scanner := bufio.NewScanner(strings.NewReader(input)) // Define a split function that separates on commas. onComma := func(data []byte, atEOF bool) (advance int, token []byte, err error) { for i := 0; i輸出
"1" "2" "3" "4" "5"你也可以用系統定義好的幾個分割token的方法。
ScanBytes 返回單個字節作為一個 token。
?
ScanRunes 返回單個 UTF-8 編碼的 rune 作為一個 token。返回的 rune 序列(token)和 range string類型 返回的序列是等價的,也就是說,對于無效的 UTF-8 編碼會解釋為 U+FFFD = "/xef/xbf/xbd"。
?
ScanWords 返回通過“空格”分詞的單詞。如:study golang,調用會返回study。注意,這里的“空格”是 unicode.IsSpace(),即包括:'/t', '/n', '/v', '/f', '/r', ' ', U+0085 (NEL), U+00A0 (NBSP)。
?
ScanLines 返回一行文本,不包括行尾的換行符。這里的換行包括了Windows下的"/r/n"和Unix下的"/n"。
?Scanner 的使用方法
- NewScanner
- Split設置分割token的方法
- 循環scanner.Scan()
- 在循環里用scanner.Text()取token 示例
const input = "This is The Golang Standard Library./nWelcome you!"scanner := bufio.NewScanner(strings.NewReader(input))scanner.Split(bufio.ScanWords)count := 0for scanner.Scan() { count++}if err := scanner.Err(); err != nil { fmt.Fprintln(os.Stderr, "reading input:", err)}fmt.Println(count)Writer
帶緩存的writer,記得在最終的寫入操作執行完后flush一下,確保全部緩存都真正寫入,如果大家想了解更多精彩內容,盡在https://js.Vevb.com。
新聞熱點
疑難解答