Go語言讀取文件的方法小結(jié)
寫程序時(shí)經(jīng)常需要從一個(gè)文件讀取數(shù)據(jù),然后輸出到另一個(gè)文件。最典型的例子比如,從stdin讀取,然后輸出到stdout。go提供了幾種讀取文件的方式,我們逐個(gè)來看一看~
fmt.Scan
func fmtScan() { str := "" for { fmt.Scan(&str) fmt.Printf("[fmt.scan]: %q (%d)\n", str, len(str)) } } // input: abc def ghi // output: //[fmt.scan]: "abc" (3) //[fmt.scan]: "def" (3) //[fmt.scan]: "ghi" (3)
fmt.Scan 從stdin讀取數(shù)據(jù),輸出到內(nèi)存變量。它會將空白符作為分割符,把分割后的字符串,依次賦值給傳入?yún)?shù)。在上面的例子中,就是循環(huán)了3次分別賦值給str。
os.Stdin.Read
func osStdinRead() { p := make([]byte, 5) for { nn, err := os.Stdin.Read(p) if err != nil && err != io.EOF { panic(err) } fmt.Printf("[os.stdin.read]: %q (%d)\n", p, nn) p = make([]byte, 5) // 清空p } } // input: abcdefghijk // output: //[os.stdin.read]: "abcde" (5) //[os.stdin.read]: "fghij" (5) //[os.stdin.read]: "k\n\x00\x00\x00" (2)
最多讀取len(p)大小的數(shù)據(jù),如果輸入的內(nèi)容超出了len(p),則Read會在下一輪循環(huán)中接著讀取。
io系列
ReadAll
func ioReadAll() { for { p, err := io.ReadAll(os.Stdin) if err != nil { panic(err) } fmt.Printf("[io.ReadAll]: %q (%d)\n", p, len(p)) } } // input: abc\nEOF // output: [io.ReadAll]: "abc\n" (4)
ReadAll 讀取全部,不把EOF當(dāng)作錯(cuò)誤返回。
ReadFull
func ioReadFull() { p := make([]byte, 5) for { nn, err := io.ReadFull(os.Stdin, p) if err != nil && err != io.EOF { fmt.Printf("[io.ReadFull]: %q (%d)\n", p, nn) panic(err) } fmt.Printf("[io.ReadFull]: %q (%d)\n", p, nn) p = make([]byte, 5) } } // input: aaaaaa // output: [io.ReadFull]: "aaaaa" (5) // input: aa\n\x00 // output: [io.ReadFull]: "aa\n\x00\x00" (3)
ReadFull 的目標(biāo)是把p填滿,也就是說正常情況下只有讀到的數(shù)據(jù)長度nn==len(p)才返回。這里有兩種情況需要注意:
- 沒有數(shù)據(jù)可讀,ReadFull返回 (0, EOF)
- 有一些數(shù)據(jù)可讀,但在填滿p前遇到了EOF,ReadFull返回 (讀取的長度, ErrUnexpectedEOF)
bufio系列
bufio給io操作提供了一個(gè)緩沖,避免了每次都要訪問磁盤。
Read
func bufioRead() { br := bufio.NewReader(os.Stdin) p := make([]byte, 5) for { nn, err := br.Read(p) if err != nil && err != io.EOF{ panic(err) } fmt.Printf("[bufio.read]: %q (%d)\n", p, nn) } } // input: abcdefghijk // output: //[bufio.read]: "abcde" (5) //[bufio.read]: "fghij" (5) //[bufio.read]: "k\n\x00\x00\x00" (2)
最多讀取len(p)大小的數(shù)據(jù),如果輸入的內(nèi)容超出了len(p),則Read會在下一輪循環(huán)中接著讀取。
ReadBytes
func bufioReadBytes() { br := bufio.NewReader(os.Stdin) for { p, err := br.ReadBytes('\n') if err != nil && err != io.EOF{ panic(err) } fmt.Printf("[bufio.ReadBytes]: %q (%d)\n", p, len(p)) } } // input: abcdef // output: [bufio.ReadBytes]: "abcdef\n" (7)
ReadBytes 讀取直到遇到給定的分界符,這里是'\n'(返回的p包含\n)。如果在讀到分界符之前遇到了err,則返回讀到的數(shù)據(jù)和err(一般是EOF)。
ReadString
func bufioReadString() { br := bufio.NewReader(os.Stdin) for { str, err := br.ReadString('\n') if err != nil && err != io.EOF { panic(err) } fmt.Printf("[bufio.ReadString]: %q (%d)\n", str, len(str)) } } // input: abcdef // output: [bufio.ReadString]: "abcdef\n" (7)
ReadString 與 ReadBytes 類似,都是直到讀到分界符才返回。
ReadRune
func bufioReadRune() { br := bufio.NewReader(os.Stdin) for { r, sz, err := br.ReadRune() if err != nil && err != io.EOF { panic(err) } fmt.Printf("[bufio.ReadRune]: %q (%d)\n", r, sz) } } // input: abc // output: //[bufio.ReadRune]: 'a' (1) //[bufio.ReadRune]: 'b' (1) //[bufio.ReadRune]: 'c' (1) //[bufio.ReadRune]: '\n' (1)
ReadRune 一次讀取一個(gè)UTF8字符。
Scan
func bufioScan() { scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { text := scanner.Text() fmt.Printf("[bufio.Scan]: %q (%d)\n", text, len(text)) } if scanner.Err() != nil { fmt.Print(scanner.Err().Error()) } }
Scan 掃描文件到下一個(gè)token并返回true,隨后可以通過Text,Bytes讀取token。當(dāng)掃描停止時(shí),Scan返回false,這時(shí)可以通過Err獲取錯(cuò)誤,如果是因?yàn)镋OF而掃描停止,Err=nil。
scanner在創(chuàng)建時(shí),默認(rèn)使用 ScanLines 作為分割函數(shù)。它會將輸入文本分割成一系列的行,每行作為一個(gè)token。除此之外還有其他分割函數(shù):
ScanLines
(默認(rèn)):按行分割。ScanWords
:按空白字符分割的單詞。ScanBytes
:按字節(jié)分割。ScanRunes
:按UTF-8編碼的字符分割。
總結(jié)
如果只是簡單從stdin讀取,fmt.Scan 足夠短小好用。當(dāng)文件很大時(shí) io.ReadAll, io.ReadFull 感覺在使用時(shí)不是很靈活,還是推薦用bufio的一系列方法操作。
到此這篇關(guān)于Go語言讀取文件的方法小結(jié)的文章就介紹到這了,更多相關(guān)Go讀取文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go的固定時(shí)長定時(shí)器和周期性時(shí)長定時(shí)器
本文主要介紹了Go的固定時(shí)長定時(shí)器和周期性時(shí)長定時(shí)器,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08Golang中生成隨機(jī)字符串并復(fù)制到粘貼板的方法
這篇文章主要介紹了Golang中生成隨機(jī)字符串并復(fù)制到粘貼板的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12golang模擬實(shí)現(xiàn)帶超時(shí)的信號量示例代碼
這篇文章主要給大家介紹了關(guān)于golang模擬實(shí)現(xiàn)帶超時(shí)的信號量的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09Golang如何編寫內(nèi)存高效及CPU調(diào)優(yōu)的Go結(jié)構(gòu)體
這篇文章主要介紹了Golang如何編寫內(nèi)存高效及CPU調(diào)優(yōu)的Go結(jié)構(gòu)體,結(jié)構(gòu)體是包含多個(gè)字段的集合類型,用于將數(shù)據(jù)組合為記錄2022-07-07