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