Go bufio
最后修改时间 2024 年 4 月 11 日
在本文中,我们将展示如何使用 bufio 包在 Golang 中执行缓冲的输入和输出操作。
bufio 包
内置的 bufio
包实现了缓冲的 IO 操作。缓冲是一种提高 IO 操作性能的技术。
由于系统调用开销很大,当我们累积数据到缓冲区进行读取或写入时,IO 操作的性能得到了极大的提高。这减少了所需的系统调用次数。
type Reader type Writer type Scanner
Reader
为 io.Reader 对象实现了缓冲。Writer
为 io.Writer 对象实现了缓冲。Scanner
为读取数据(如逐行文本文件)提供了一个方便的接口。
使用 bufio.NewReader
或 bufio.NewReaderSize
创建新读取器。
func NewReader(rd io.Reader) *Reader func NewReaderSize(rd io.Reader, size int) *Reader
NewReader
函数返回一个新读取器,其缓冲区具有默认大小。NewReaderSize
返回一个新读取器,其缓冲区至少具有指定的大小。
使用 bufio.NewWriter
或 bufio.NewWriterSize
创建新写入器。
func NewWriter(w io.Writer) *Writer func NewWriterSize(w io.Writer, size int) *Writer
NewWriter
函数返回一个新写入器,其缓冲区具有默认大小。NewWriterSize
返回一个新写入器,其缓冲区至少具有指定的大小。
使用 bufio.NewScanner
创建新扫描器。
func NewScanner(r io.Reader) *Scanner
NewScanner
返回一个新扫描器以从 r 读取。分隔符函数默认为 ScanLines
。
func (b *Writer) Flush() error
Flush
将任何缓冲数据写入底层 io.Writer。
Go Reader.ReadString
ReadString
读取直到输入中第一个给定分隔符的出现。
func (b *Reader) ReadString(delim byte) (string, error)
它返回一个包含到分隔符为止(包括分隔符)的数据的字符串。
package main import ( "bufio" "fmt" "log" "os" "strings" ) func main() { fmt.Print("Enter your name: ") r := bufio.NewReader(os.Stdin) name, err := r.ReadString('\n') if err != nil { log.Fatal(err) } fmt.Printf("Hello %s!\n", strings.TrimSpace(name)) }
使用 ReadString
函数,我们从用户那里读取输入,并将消息输出到控制台。
r := bufio.NewReader(os.Stdin)
我们从标准输入创建一个新的读取器。
name, err := r.ReadString('\n')
从用户那里读取一个字符串输入。
$ go run main.go Enter your name: Jan Hello Jan!
Go Writer.WriteString
WriteString
将字符串写入缓冲区。
func (b *Writer) WriteString(s string) (int, error)
它返回写入的字节数。
package main import ( "bufio" "fmt" "log" "os" ) func main() { data := []string{"an old falcon", "misty mountains", "a wise man", "a rainy morning"} f, err := os.Create("words.txt") if err != nil { log.Fatal(err) } defer f.Close() wr := bufio.NewWriter(f) for _, line := range data { wr.WriteString(line + "\n") } wr.Flush() fmt.Println("data written") }
该示例使用 Writer.WriteString
将几个字符串写入文件。
wr := bufio.NewWriter(f)
创建一个新的写入器。默认缓冲区大小为 4KB。
for _, line := range data { wr.WriteString(line + "\n") }
在 for 循环中,我们将数据写入缓冲区。
wr.Flush()
由于我们的数据小于默认的 4KB 缓冲区大小,我们必须调用 Flush
才能将数据实际写入文件。
使用 Scanner 逐行读取文件
在下一个示例中,我们将使用 Scanner 逐行读取文件。
sky nice cup cloud forest water pond lake snow
这是 words.txt
文件。
package main import ( "bufio" "fmt" "log" "os" ) func main() { f, err := os.Open("words.txt") if err != nil { log.Fatal(err) } defer f.Close() scanner := bufio.NewScanner(f) for scanner.Scan() { fmt.Println(scanner.Text()) } if err := scanner.Err(); err != nil { log.Fatal(err) } }
该示例读取一个包含每行一个单词的小文件。
scanner := bufio.NewScanner(f)
使用 bufio.NewScanner
创建新扫描器。
for scanner.Scan() { fmt.Println(scanner.Text()) }
Scan
函数将 Scanner 前进到下一个标记,该标记随后可通过 Bytes
或 Text
方法访问。默认情况下,该函数按行前进。
$ go run main.go sky nice cup cloud forest water pond lake snow
从字符串中读取单词
在下面的示例中,我们使用 Scanner 从字符串中读取单词。
package main import ( "bufio" "fmt" "log" "strings" ) func main() { words := []string{} data := "A foggy mountain.\nAn old falcon.\nA wise man." sc := bufio.NewScanner(strings.NewReader(data)) sc.Split(bufio.ScanWords) n := 0 for sc.Scan() { words = append(words, sc.Text()) n++ } if err := sc.Err(); err != nil { log.Fatal(err) } fmt.Printf("# of words: %d\n", n) for _, word := range words { fmt.Println(word) } }
strings.NewReader
从字符串返回一个新读取器。
sc.Split(bufio.ScanWords)
我们通过使用 Split
告诉扫描器按单词扫描。
Go Writer.WriteRune
WriteRune
写入单个 rune。
func (b *Writer) WriteRune(r rune) (size int, err error)
它返回写入的字节数和任何错误。
package main import ( "bufio" "fmt" "log" "os" ) func main() { runes := "🐜🐬🐄🐘🦂🐫🐑🦍🐯🐞" f, err := os.Create("runes.txt") if err != nil { log.Fatal(err) } defer f.Close() wr := bufio.NewWriter(f) for _, _rune := range runes { wr.WriteRune(_rune) wr.WriteRune('\n') } wr.Flush() fmt.Println("runes written") }
在示例中,我们从字符串读取 rune 并将它们写入文件;每行一个。
Go Reader.Read
Reader.Read
函数将数据读取到字节切片中。
func (b *Reader) Read(p []byte) (n int, err error)
它返回读取的字节数。
在下一个示例中,我们还使用了 hex
包,它实现了十六进制编码和解码。
package main import ( "bufio" "encoding/hex" "fmt" "log" "os" "io" ) func main() { f, err := os.Open("sid.jpg") if err != nil { log.Fatal(err) } defer f.Close() reader := bufio.NewReader(f) buf := make([]byte, 256) for { _, err := reader.Read(buf) if err != nil { if err != io.EOF { fmt.Println(err) } break } fmt.Printf("%s", hex.Dump(buf)) } }
在代码示例中,我们读取一个图像并以十六进制格式打印它。
reader := bufio.NewReader(f)
我们使用 bufio.NewReader
创建一个读取器。
buf := make([]byte, 256)
我们创建了一个 256 字节的自定义缓冲区。
for { _, err := reader.Read(buf) ...
我们在 for 循环中读取二进制数据。
fmt.Printf("%s", hex.Dump(buf))
Dump
返回一个包含给定数据十六进制转储的字符串。
$ go run main.go 00000000 ff d8 ff e0 00 10 4a 46 49 46 00 01 01 00 00 01 |......JFIF......| 00000010 00 01 00 00 ff e1 00 2f 45 78 69 66 00 00 49 49 |......./Exif..II| 00000020 2a 00 08 00 00 00 01 00 0e 01 02 00 0d 00 00 00 |*...............| 00000030 1a 00 00 00 00 00 00 00 6b 69 6e 6f 70 6f 69 73 |........kinopois| 00000040 6b 2e 72 75 00 ff fe 00 3b 43 52 45 41 54 4f 52 |k.ru....;CREATOR| 00000050 3a 20 67 64 2d 6a 70 65 67 20 76 31 2e 30 20 28 |: gd-jpeg v1.0 (| 00000060 75 73 69 6e 67 20 49 4a 47 20 4a 50 45 47 20 76 |using IJG JPEG v| 00000070 38 30 29 2c 20 71 75 61 6c 69 74 79 20 3d 20 39 |80), quality = 9| 00000080 31 0a ff db 00 43 00 03 02 02 03 02 02 03 03 02 |1....C..........| 00000090 03 03 03 03 03 04 07 05 04 04 04 04 09 06 07 05 |................| 000000a0 07 0a 09 0b 0b 0a 09 0a 0a 0c 0d 11 0e 0c 0c 10 |................| 000000b0 0c 0a 0a 0e 14 0f 10 11 12 13 13 13 0b 0e 14 16 |................| ...
来源
在本文中,我们使用了 Go 中的 bufio 包。