Go 语言标准库 bufio 详解

开发 前端
本文我们以 bufio.Reader 为例,介绍标准库 bufio 的数据类型、初始化方式和提供的方法。

​01 介绍

Go 语言标准库 bufio​ 是基于 Go 语言标准库 io​ 实现的,查看源码可以发现,实际上它是包装了 io.Reader​ 接口和 io.Writer 接口,并且实现它们。

bufio 顾名思义,就是在缓冲区读写数据,比直接读写文件或网络中的数据,性能更好些。

本文我们介绍 bufio​ 的相关内容,建议读者朋友们最好是先了解一下 io 的相关内容。

02 标准库 bufio 的数据类型

查看标准库 `bufio` 的文档[1],它的数据类型主要有 bufio.Reader、bufio.Writer、bufio.ReadWriter​ 和 bufio.Scanner。

我们以 bufio.Reader 为例,介绍它的数据结构、初始化方式和提供的方法。

bufio.Reader 的数据结构:

type Reader struct {
buf []byte
rd io.Reader
r, w int
err error
lastByte int
lastRuneSize int
}

阅读源码,我们可以发现 bufio.Reader 中包含的字段:

  • buf []byte 缓冲区。
  • rd io.Reader 缓冲区的数据源。
  • r,w int 缓冲区读写索引位置。
  • err error 错误。
  • lastByte int 未读字节的上一个字节。
  • lastRuneSize 未读字符的上一个字符的大小。

bufio.Reader 的初始化方式:

使用 bufio.Reader​ 时,需要先初始化,bufio​ 包提供了两个初始化的函数,分别是 NewReaderSize​ 和 NewReader。

func NewReaderSize(rd io.Reader, size int) *Reader {
// Is it already a Reader?
b, ok := rd.(*Reader)
if ok && len(b.buf) >= size {
return b
}
if size < minReadBufferSize {
size = minReadBufferSize
}
r := new(Reader)
r.reset(make([]byte, size), rd)
return r
}

func NewReader(rd io.Reader) *Reader {
return NewReaderSize(rd, defaultBufSize)
}

阅读源码,我们可以发现这两个函数的返回值都是 *bufio.Reader 类型。

其中 NewReader​ 是包装了 NewReaderSize 函数,给定了一个默认值 4096,设置读缓冲区的大小。

如果我们使用默认值,一般选择使用 NewReader 函数。

如果不想使用默认值,可以选择使用 NewReaderSize 函数。

bufio.Reader 提供的方法:

bufio.Reader​ 提供了 15 个方法,我们介绍两个比较常用的方法,分别是 Read​ 和 ReadBytes。

func (b *Reader) Read(p []byte) (n int, err error) {
// 省略代码 ...
if b.r == b.w {
if b.err != nil {
return 0, b.readErr()
}
if len(p) >= len(b.buf) {
// Large read, empty buffer.
// Read directly into p to avoid copy.
n, b.err = b.rd.Read(p)
if n < 0 {
panic(errNegativeRead)
}
if n > 0 {
b.lastByte = int(p[n-1])
b.lastRuneSize = -1
}
return n, b.readErr()
}
// 省略代码 ...
b.w += n
}

// copy as much as we can
// Note: if the slice panics here, it is probably because
// the underlying reader returned a bad count. See issue 49795.
n = copy(p, b.buf[b.r:b.w])
b.r += n
b.lastByte = int(b.buf[b.r-1])
b.lastRuneSize = -1
return n, nil
}

阅读源码,我们可以发现 Read​ 方法是将缓冲区中的数据,读取到 p 中,并返回读取的字节大小和错误。

func (b *Reader) ReadBytes(delim byte) ([]byte, error) {
full, frag, n, err := b.collectFragments(delim)
// Allocate new buffer to hold the full pieces and the fragment.
buf := make([]byte, n)
n = 0
// Copy full pieces and fragment in.
for i := range full {
n += copy(buf[n:], full[i])
}
copy(buf[n:], frag)
return buf, err
}

阅读源码,我们可以发现 ReadBytes​ 方法是读取缓冲区中的数据截止到分隔符 delim 的位置,并返回数据和错误。

使用示例:

Read 方法

func main() {
f, _ := os.Open("/Users/frank/GolandProjects/go-package/lesson14/file.txt")
defer f.Close()
r := bufio.NewReader(f)
p := make([]byte, 12)
index, _ := r.Read(p)
fmt.Println(index)
fmt.Println(string(p[:index]))
}

需要注意的是,p 字节切片的长度,一个中文字符是 3 个字节,一个英文字符是 1 个字节。

ReadBytes 方法

func main() {
f, _ := os.Open("/Users/frank/GolandProjects/go-package/lesson14/file.txt")
defer f.Close()
r := bufio.NewReader(f)
bs, _ := r.ReadBytes('\n')
fmt.Println(string(bs))
}

需要注意的是,分隔符参数是 byte 类型,使用单引号。

03 总结

本文我们以 bufio.Reader​ 为例,介绍标准库 bufio 的数据类型、初始化方式和提供的方法。

实际上标准库 bufio 使用非常简单,但是想要避免踩 “坑”,读者朋友们最好是熟读标准库 `bufio` 的源码[2]。

参考资料

[1]标准库 bufio​ 的文档: https://pkg.go.dev/bufio@go1.20.2

[2]标准库 bufio​ 的源码: https://cs.opensource.google/go/go/+/refs/tags/go1.20.2:src/bufio/

责任编辑:武晓燕 来源: Golang语言开发栈
相关推荐

2023-09-07 07:35:54

GolangBufio

2023-10-10 08:57:44

Golangbufio

2023-10-07 09:08:32

Golangbufio

2023-09-27 08:26:48

Go标准库函数

2014-01-14 09:10:53

GoHTTP内存泄漏

2021-10-18 10:53:26

Go 代码技术

2024-10-28 00:40:49

Go语法版本

2023-02-10 09:40:36

Go语言并发

2023-10-18 08:22:38

BufioGolang

2021-08-13 12:05:15

Goneturl

2021-02-06 18:19:54

TimeGo语言

2020-02-11 09:41:02

Go语言程序员文章

2020-02-05 16:55:11

Go语言程序员文章

2024-07-11 08:50:05

Go语言errors

2024-05-10 08:04:44

开发者Go语言

2023-04-09 23:09:59

Go语言函数

2024-09-29 16:04:14

2023-10-07 00:10:27

日志格式函数

2021-12-10 15:22:26

Go Zip 文件

2023-02-13 00:24:37

Go语言日志库
点赞
收藏

51CTO技术栈公众号