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

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

概述

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) // 写入一个字符串

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

推荐文章

你可能不知道的 18 个前端技巧
2025-06-12 13:15:26 +0800 CST
Java环境中使用Elasticsearch
2024-11-18 22:46:32 +0800 CST
乐观锁和悲观锁,如何区分?
2024-11-19 09:36:53 +0800 CST
Hypothesis是一个强大的Python测试库
2024-11-19 04:31:30 +0800 CST
使用Python提取图片中的GPS信息
2024-11-18 13:46:22 +0800 CST
一个有趣的进度条
2024-11-19 09:56:04 +0800 CST
Nginx 负载均衡
2024-11-19 10:03:14 +0800 CST
Vue3中怎样处理组件引用?
2024-11-18 23:17:15 +0800 CST
跟着 IP 地址,我能找到你家不?
2024-11-18 12:12:54 +0800 CST
一些高质量的Mac软件资源网站
2024-11-19 08:16:01 +0800 CST
CSS Grid 和 Flexbox 的主要区别
2024-11-18 23:09:50 +0800 CST
小技巧vscode去除空格方法
2024-11-17 05:00:30 +0800 CST
Vue 中如何处理父子组件通信?
2024-11-17 04:35:13 +0800 CST
OpenCV 检测与跟踪移动物体
2024-11-18 15:27:01 +0800 CST
File 和 Blob 的区别
2024-11-18 23:11:46 +0800 CST
网络数据抓取神器 Pipet
2024-11-19 05:43:20 +0800 CST
Rust 中的所有权机制
2024-11-18 20:54:50 +0800 CST
git使用笔记
2024-11-18 18:17:44 +0800 CST
总结出30个代码前端代码规范
2024-11-19 07:59:43 +0800 CST
程序员茄子在线接单