Gobufio教程展示了如何使用bufio包在Golang中进行缓冲输入和输出操作。
$ go version go version go1.18.1 linux/amd64
我们使用Go版本1.18。
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
函数返回一个新的Reader,其缓冲区具有默认大小。NewReaderSize
返回一个新的Reader,其缓冲区至少具有指定的大小。
使用bufio.NewWriter
或bufio.NewWriterSize
创建了一个新的编写器。
func NewWriter(w io.Writer) *Writer func NewWriterSize(w io.Writer, size int) *Writer
NewWriter
函数返回一个新的Writer,其缓冲区具有默认大小。NewWriterSize
返回一个新的Writer,其缓冲区至少具有指定的大小。
使用bufio.NewScanner
创建了一个新的扫描器。
func NewScanner(r io.Reader) *Scanner
NewScanner
返回一个新的Scanner以从r中读取。splitfunction默认为ScanLines
。
func (b *Writer) Flush() error
Flush
将任何缓冲数据写入底层io.Writer。
GoReader.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!
GoWriter.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
函数将扫描器推进到下一个令牌,然后可以通过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
告诉扫描仪按单词扫描。
GoWriter.WriteRune
WriteRune
写入单个符文。
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") }
在示例中,我们从字符串中读取符文并将它们写入文件;每一个在一个单独的行上。
GoReader.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包。
列出所有Go教程。