Go語言中緩沖bufio的原理解讀與應(yīng)用實戰(zhàn)
bufio是Go語言標準庫中的一個重要包,它提供了帶緩沖的I/O操作,用于包裝io.Reader或io.Writer對象,以減少I/O操作的次數(shù),從而提高讀寫性能。本文將結(jié)合實際案例,詳細講解bufio在Go語言中的用法。
Go語言自帶的IO操作包。bufio,使用這個包可以大幅提升文件的讀寫效率。
- buf: 緩沖區(qū).
- io操作效率本身是還可以的,頻繁訪問本地磁盤文件(效率低)
所以說 bufio ,提供了一個緩沖區(qū),讀和寫都先在緩沖區(qū)中,最后再一次性讀取或者寫入到文件里,降低訪問本地磁盤的次數(shù)。
一、bufio的基本概念和原理
bufio的主要作用是減少I/O操作的次數(shù),提供讀寫性能。其工作原理是通過在內(nèi)存中維護一個緩沖區(qū),先將數(shù)據(jù)讀入緩沖區(qū),再從緩沖區(qū)中讀取數(shù)據(jù),從而減少對底層I/O設(shè)備的訪問次數(shù)。
bufio的主要對象是緩沖區(qū),操作主要有兩個:讀和寫。讀操作時,如果緩沖區(qū)為空,則從文件讀取數(shù)據(jù)填滿緩沖區(qū);如果緩沖區(qū)不為空,則從緩沖區(qū)讀取數(shù)據(jù)。寫操作時,如果緩沖區(qū)未滿,則將數(shù)據(jù)寫入緩沖區(qū);如果緩沖區(qū)已滿,則將緩沖區(qū)的數(shù)據(jù)寫入文件,并繼續(xù)寫入剩余的數(shù)據(jù)。
二、bufio的讀操作
bufio的讀操作主要通過bufio.Reader對象實現(xiàn),它提供了多種讀取數(shù)據(jù)的方法,如Read、ReadLine、ReadString等。
1. 使用bufio.Reader讀取文件內(nèi)容
下面是一個使用bufio.Reader讀取文件內(nèi)容的示例:
package main import ( "bufio" "fmt" "io" "os" ) func main() { // 打開文件 file, err := os.Open("example.txt") if err != nil { fmt.Println("read file err:", err) return } defer file.Close() // 使用defer關(guān)閉文件 // 創(chuàng)建bufio.Reader對象。借助bufio來讀取文件內(nèi)容 // func NewReader(rd io.Reader) *Reader reader := bufio.NewReader(file) // 循環(huán)讀取文件內(nèi)容 for { // 通過Read方法Read()讀取文件 //buf := make([]byte, 1024) //n, err := bufioReader.Read(buf) //fmt.Println("讀取到了多少個字節(jié):", n) //讀取到的內(nèi)容 //fmt.Println("讀取到的內(nèi)容:",string(buf[:n])) //通過ReadString方法讀取文件 // func (b *Reader) ReadString(delim byte) (string, error) //參數(shù)是以什么作為分隔符。讀取得到的是字符串 //注意,最后一行后面要是沒有換行符,讀取不到 str, err := reader.ReadString('\n') // 讀取字符串,以換行符為分隔符 if err == io.EOF { // 判斷文件是否結(jié)尾 break } else if err != nil { // 判斷錯誤,打印錯誤 fmt.Printf("read file failed, err:%v", err) break } //循環(huán)中逐行打印出讀取的內(nèi)容 fmt.Printf("read string SuccessFull: %s\n", str) // 打印讀取的文件內(nèi)容 } }
在這個示例中,我們首先使用os.Open函數(shù)打開文件,然后創(chuàng)建一個bufio.Reader對象,通過循環(huán)調(diào)用ReadString方法讀取文件內(nèi)容,每次讀取一行。當(dāng)遇到文件結(jié)尾時,ReadString方法會返回一個io.EOF錯誤,我們據(jù)此退出循環(huán)。
2. 統(tǒng)計文件中字符、空格、數(shù)字和其他字符的數(shù)量
下面是一個統(tǒng)計文件中字符、空格、數(shù)字和其他字符數(shù)量的示例:
package main import ( "bufio" "fmt" "io" "os" ) // CharCount 定義結(jié)構(gòu)體 type CharCount struct { ChCount int NumCount int SpaceCount int OtherCount int } func main() { // 打開文件 file, err := os.Open("example.txt") if err != nil { fmt.Println("read file err:", err) return } defer file.Close() // 使用defer關(guān)閉文件 // 創(chuàng)建bufio.Reader對象 reader := bufio.NewReader(file) var count CharCount // 循環(huán)讀取文件內(nèi)容 for { //str, err := reader.ReadString('\n') // 讀取字符串,以換行符為分隔符 str, _, err := reader.ReadLine() // 按行讀取,最后一行沒有換行符也能讀到 if err == io.EOF { // 判斷文件是否結(jié)尾 break } if err != nil { // 判斷錯誤,打印錯誤 fmt.Printf("read file failed, err:%v", err) break } //runeArr := []rune(str) // 將字符串轉(zhuǎn)為切片類型 runeArr := str // 將字符串轉(zhuǎn)為切片類型 fmt.Println("得到的數(shù)據(jù)是", string(runeArr)) for _, v := range runeArr { // 循環(huán)讀取數(shù)組 switch { case v >= 'a' && v <= 'z': // 判斷是不是小寫字母 fallthrough case v >= 'A' && v <= 'Z': // 判斷是不是大寫字母 count.ChCount++ case v == ' ' || v == '\t': // 判斷是不是空格 count.SpaceCount++ case v >= '0' && v <= '9': // 判斷是不是數(shù)字 count.NumCount++ default: count.OtherCount++ } } } fmt.Printf("char count:%d\n", count.ChCount) fmt.Printf("num count:%d\n", count.NumCount) fmt.Printf("space count:%d\n", count.SpaceCount) fmt.Printf("other count:%d\n", count.OtherCount) }
3. 使用Scanner讀取標準輸入
下面是一個使用bufio.Scanner讀取標準輸入的示例:
package main import ( "bufio" "fmt" "os" ) func main() { // 讀取鍵盤的輸入 // 鍵盤的輸入,實際上是流 os.Stdin inputReader := bufio.NewReader(os.Stdin) // delim 到哪里結(jié)束讀取 以換行符作為分隔符,之言不換行就可以一直讀 readString, _ := inputReader.ReadString('\n') fmt.Println("讀取鍵盤輸入的信息:", readString) }
三、bufio的寫操作
bufio的寫操作主要通過bufio.Writer對象實現(xiàn),它提供了多種寫入數(shù)據(jù)的方法,如Write、WriteString、Flush等。
1. 使用bufio.Writer寫入文件內(nèi)容
下面是一個使用bufio.Writer寫入文件內(nèi)容的示例:
package main import ( "bufio" "fmt" "os" ) func main() { // 打開文件句柄,以寫的方式打開,如果文件不存在則創(chuàng)建 file, err := os.OpenFile("F:\\goworks\\src\\jingtian\\yufa\\io操作\\bufio操作\\test_go_file.log", os.O_CREATE|os.O_WRONLY, 0644) if err != nil { fmt.Println("open file error:", err) return } defer file.Close() // 使用的defer語句關(guān)閉文件 // 創(chuàng)建bufio.Writer對象 fileWrite := bufio.NewWriter(file) inputStr := "Hello World ...\n" for i := 0; i < 10; i++ { // 循環(huán)寫入數(shù)據(jù) fileWrite.WriteString(inputStr) } // 發(fā)現(xiàn)并沒有寫出到文件,是留在了緩沖區(qū),所以我們需要調(diào)用 flush 刷新緩沖區(qū) // 必須手動刷新才能寫入進文件 fileWrite.Flush() // 刷新緩沖區(qū),將數(shù)據(jù)寫入文件 }
在這個示例中,我們首先使用os.OpenFile函數(shù)打開文件,然后創(chuàng)建一個bufio.Writer對象,通過循環(huán)調(diào)用WriteString方法寫入文件內(nèi)容。最后,我們調(diào)用Flush方法刷新緩沖區(qū),將數(shù)據(jù)寫入文件。
2. 自定義io.Writer對象進行緩沖寫
下面是一個自定義io.Writer對象進行緩沖寫的示例:
package main import ( "bufio" "fmt" "io" "strings" ) // 自定義一個io.Writer對象 type StringWriter struct{} func (s StringWriter) Write(p []byte) (n int, err error) { // 這里簡單地將數(shù)據(jù)寫入一個字符串變量(實際使用時,可以將其寫入內(nèi)存、文件等) fmt.Print(string(p)) return len(p), nil } func main() { // 創(chuàng)建一個StringWriter對象 sw := StringWriter{} // 創(chuàng)建一個bufio.Writer對象,并傳入StringWriter對象 writer := bufio.NewWriterSize(sw, 10) // 寫入數(shù)據(jù) writer.WriteString("Hello, ") writer.WriteString("world!\n") // 刷新緩沖區(qū),將數(shù)據(jù)寫入StringWriter對象 writer.Flush() }
在這個示例中,我們自定義了一個StringWriter對象,它實現(xiàn)了io.Writer接口的Write方法。然后,我們創(chuàng)建一個bufio.Writer對象,并傳入StringWriter對象。接著,我們調(diào)用WriteString方法寫入數(shù)據(jù),并調(diào)用Flush方法刷新緩沖區(qū),將數(shù)據(jù)寫入StringWriter對象。
四、bufio的緩沖區(qū)大小
在bufio包中,Reader和Writer對象都有默認的緩沖區(qū)大小,但你也可以根據(jù)需要自定義緩沖區(qū)大小。
1. 默認緩沖區(qū)大小
對于bufio.Reader
和bufio.Writer
,Go語言標準庫為它們提供了默認的緩沖區(qū)大小。對于bufio.Reader
,默認緩沖區(qū)大小通常是4096字節(jié)(4KB);對于bufio.Writer
,默認緩沖區(qū)大小也是4096字節(jié)(但在某些實現(xiàn)中可能略有不同,具體取決于底層操作系統(tǒng)的I/O性能)。
2. 自定義緩沖區(qū)大小
如果你需要更大的緩沖區(qū)來提高性能,或者更小的緩沖區(qū)來減少內(nèi)存使用,你可以使用bufio.NewReaderSize
和bufio.NewWriterSize
函數(shù)來創(chuàng)建具有自定義緩沖區(qū)大小的Reader和Writer對象。
下面是一個自定義緩沖區(qū)大小的示例:
package main import ( "bufio" "fmt" "os" ) func main() { // 打開文件 file, err := os.OpenFile("F:\\goworks\\src\\jingtian\\yufa\\io操作\\bufio操作\\custom_buffer_file.log", os.O_CREATE|os.O_WRONLY, 0644) if err != nil { fmt.Println("open file error:", err) return } defer file.Close() // 使用defer語句關(guān)閉文件 // 自定義緩沖區(qū)大?。ɡ纾?KB) bufferSize := 8 * 1024 // 創(chuàng)建具有自定義緩沖區(qū)大小的bufio.Writer對象 fileWrite := bufio.NewWriterSize(file, bufferSize) inputStr := "This is a line with custom buffer size.\n" for i := 0; i < 10; i++ { // 循環(huán)寫入數(shù)據(jù) _, err := fileWrite.WriteString(inputStr) if err != nil { fmt.Println("write file error:", err) return } } // 刷新緩沖區(qū),將數(shù)據(jù)寫入文件 err = fileWrite.Flush() if err != nil { fmt.Println("flush buffer error:", err) return } fmt.Println("Data written to file successfully with custom buffer size.") }
在這個示例中,我們創(chuàng)建了一個具有8KB緩沖區(qū)大小的bufio.Writer
對象,并將其用于將數(shù)據(jù)寫入文件。注意,在寫入數(shù)據(jù)后,我們調(diào)用了Flush
方法來確保緩沖區(qū)中的數(shù)據(jù)被寫入文件。
對于bufio.Reader
,你也可以使用類似的方法來創(chuàng)建具有自定義緩沖區(qū)大小的對象:
package main import ( "bufio" "fmt" "os" ) func main() { // 打開文件 file, err := os.Open("F:\\goworks\\src\\jingtian\\yufa\\io操作\\bufio操作\\custom_buffer_file.log") if err != nil { fmt.Println("read file error:", err) return } defer file.Close() // 使用defer語句關(guān)閉文件 // 自定義緩沖區(qū)大小(例如:8KB) bufferSize := 8 * 1024 // 創(chuàng)建具有自定義緩沖區(qū)大小的bufio.Reader對象 fileRead := bufio.NewReaderSize(file, bufferSize) // 讀取文件內(nèi)容(這里只是簡單地讀取并打印每一行) for { line, err := fileRead.ReadString('\n') if err != nil { if err.Error() == "EOF" { // 判斷是否到達文件末尾 break } fmt.Println("read file error:", err) return } fmt.Print(line) // 打印讀取到的行 } fmt.Println("File read successfully with custom buffer size.") }
在這個示例中,我們創(chuàng)建了一個具有8KB緩沖區(qū)大小的bufio.Reader
對象,并將其用于讀取文件內(nèi)容。注意,在處理文件讀取時,我們需要檢查錯誤是否為EOF
(文件末尾),以確定是否應(yīng)該退出循環(huán)。
通過自定義緩沖區(qū)大小,你可以根據(jù)具體的應(yīng)用場景和需求來優(yōu)化bufio的性能和內(nèi)存使用。
到此這篇關(guān)于Go語言中緩沖bufio的原理解讀與應(yīng)用實戰(zhàn)的文章就介紹到這了,更多相關(guān)Go語言緩沖bufio內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang實現(xiàn)微信小程序商城后臺系統(tǒng)(moshopserver)
這篇文章主要介紹了golang實現(xiàn)微信小程序商城后臺系統(tǒng)(moshopserver),本文通過截圖實例代碼的形式給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2020-02-02Golang 實現(xiàn)interface類型轉(zhuǎn)string類型
這篇文章主要介紹了Golang 實現(xiàn)interface類型轉(zhuǎn)string類型的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04Golang HTTP請求Json響應(yīng)解析方法以及解讀失敗的原因
這篇文章主要介紹了Golang HTTP請求Json響應(yīng)解析方法以及解讀失敗的原因,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03