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 包。