编程 Go语言中的`bufio`包,它是对`io`包的封装,提供了数据缓冲功能以提高读写效率

2024-11-19 09:44:38 +0800 CST views 530

概述

bufio 包是对 io 包的封装,提供了数据缓冲功能,能够在处理大块数据读写时减少开销。在 bufio 中,各个组件内部都维护了一个缓冲区。数据的读写操作首先通过缓冲区进行,只有当缓冲区没有数据时,才会从数据源获取数据并更新缓冲区。

Reader

可以通过 NewReader 函数创建 bufio.Reader 对象。该函数接收一个 io.Reader 作为参数,这意味着 bufio.Reader 需要绑定到某个 io.Reader 上才能使用。函数声明如下:

func NewReader(rd io.Reader) *Reader

func NewReaderSize(rd io.Reader, size int) *Reader // 可以配置缓冲区的大小

相比于 io.Readerbufio.Reader 提供了更多实用的方法,以更有效地读取数据。以下是几个基础方法,它们能够对 Reader 进行细粒度的操作:

  • Read:读取指定长度的字节数据。
  • Discard:丢弃接下来指定长度的字节数据。
  • Peek:获取缓冲区内接下来的字节数据,但不移动指针。
  • Reset:清空整个缓冲区并绑定新的 io.Reader

具体方法声明如下:

func (b *Reader) Read(p []byte) (n int, err error)

func (b *Reader) Discard(n int) (discarded int, err error)

func (b *Reader) Peek(n int) ([]byte, error)

func (b *Reader) Reset(r io.Reader)

除了基础操作,bufio.Reader 还提供了更多高级抽象层次的方法,用于简化数据的结构化读取。主要包括以下几个方法:

  • ReadByte:读取一个字节。
  • ReadRune:读取一个 UTF-8 字符。
  • ReadLine:按行读取数据(由 \n 分隔)。
  • ReadBytes:读取一个字节列表,直到遇到指定分隔符。
  • ReadString:读取一个字符串,直到遇到指定分隔符。

其中前三个函数无参数,直接从缓冲区读取满足需求的数据。后两个函数接收一个 delim 参数,用于分隔数据,持续读取数据直到遇到该分隔符,然后返回读取的数据。具体方法声明如下:

func (b *Reader) ReadByte() (byte, error)

func (b *Reader) ReadRune() (r rune, size int, err error)

func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)

func (b *Reader) ReadBytes(delim byte) ([]byte, error)

func (b *Reader) ReadString(delim byte) (string, error)

下面是一个使用 ReadString 方法读取以空格分隔的字符串的示例:

package main

import (
	"bufio"
	"fmt"
	"strings"
)

func main() {
	r := strings.NewReader("hello world !")
	reader := bufio.NewReader(r)

	for {
		str, err := reader.ReadString(byte(' '))
		fmt.Println(str)
		if err != nil {
			return
		}
	}
}

Scanner

实际使用中,更推荐使用 Scanner 进行数据读取,而非直接使用 Reader 类。Scanner 可以通过 splitFunc 将输入数据拆分为多个 token,然后依次进行读取。

Reader 类似,Scanner 需要绑定到某个 io.Reader 上,通过 NewScanner 创建,函数声明如下:

func NewScanner(r io.Reader) *Scanner

使用 Scanner 之前,需要设置 splitFunc(默认为 ScanLines)。splitFunc 用于将输入数据拆分为多个 tokenbufio 模块提供了几个默认的 splitFunc,能够满足大部分场景需求,包括:

  • ScanBytes:按字节拆分。
  • ScanLines:按行(\n)拆分。
  • ScanRunes:按 UTF-8 字符拆分。
  • ScanWords:按单词(空格)拆分。

通过 ScannerSplit 方法可以指定 splitFunc。使用方法如下:

scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)

此外,用户还可以定义自己的 splitFunc,其函数声明如下:

type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)

完成 Scanner 初始化后,通过 Scan 方法可以依次读取每个 token。读取成功返回 true,可通过 TextBytes 方法获取 token 值,Text 返回字符串,Bytes 返回字节数组。方法声明如下:

func (s *Scanner) Scan() bool

func (s *Scanner) Text() string

func (s *Scanner) Bytes() []byte

以下示例使用 Scanner 对上面的示例进行了重现,可以看到与 Reader 相比,Scanner 使用更加便捷:

package main

import (
	"bufio"
	"strings"
	"fmt"
)

func main() {
	scanner := bufio.NewScanner(strings.NewReader("hello world !"))
	scanner.Split(bufio.ScanWords)

	for scanner.Scan() {
		fmt.Println(scanner.Text())
	}
}

Writer

Reader 类似,bufio.Writer 也提供了一组方法用于数据写入。基础方法包括:

func (b *Writer) Write(p []byte) (nn int, err error) // 写入字节数据

func (b *Writer) Reset(w io.Writer) // 重置当前缓冲区

func (b *Writer) Flush() error // 刷新缓冲区,将数据写入输出

此外,Writer 还提供了以下便捷方法:

func (b *Writer) WriteByte(c byte) error  // 写入一个字节

func (b *Writer) WriteRune(r rune) (size int, err error) // 写入一个字符

func (b *Writer) WriteString(s string) (int, error) // 写入一个字符串

通过这些方法,开发者可以更灵活、高效地处理数据的读写操作。

推荐文章

liunx服务器监控workerman进程守护
2024-11-18 13:28:44 +0800 CST
Go语言中的mysql数据库操作指南
2024-11-19 03:00:22 +0800 CST
ElasticSearch集群搭建指南
2024-11-19 02:31:21 +0800 CST
go错误处理
2024-11-18 18:17:38 +0800 CST
JavaScript设计模式:观察者模式
2024-11-19 05:37:50 +0800 CST
API 管理系统售卖系统
2024-11-19 08:54:18 +0800 CST
MySQL 优化利剑 EXPLAIN
2024-11-19 00:43:21 +0800 CST
Requests库详细介绍
2024-11-18 05:53:37 +0800 CST
Vue3中的JSX有什么不同?
2024-11-18 16:18:49 +0800 CST
PHP来做一个短网址(短链接)服务
2024-11-17 22:18:37 +0800 CST
全栈工程师的技术栈
2024-11-19 10:13:20 +0800 CST
Vue3中的v-for指令有什么新特性?
2024-11-18 12:34:09 +0800 CST
Hypothesis是一个强大的Python测试库
2024-11-19 04:31:30 +0800 CST
css模拟了MacBook的外观
2024-11-18 14:07:40 +0800 CST
MySQL数据库的36条军规
2024-11-18 16:46:25 +0800 CST
nuxt.js服务端渲染框架
2024-11-17 18:20:42 +0800 CST
Vue3的虚拟DOM是如何提高性能的?
2024-11-18 22:12:20 +0800 CST
程序员茄子在线接单