Go 语言标准库 bufio 详解

简介: Go 语言标准库 bufio 详解

介绍

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

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

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

查看标准库 `bufio` 的文档[1],它的数据类型主要有 bufio.Readerbufio.Writerbufio.ReadWriterbufio.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 包提供了两个初始化的函数,分别是 NewReaderSizeNewReader

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 个方法,我们介绍两个比较常用的方法,分别是 ReadReadBytes

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/

目录
打赏
0
1
1
0
8
分享
相关文章
|
3天前
|
公司局域网管理系统里的 Go 语言 Bloom Filter 算法,太值得深挖了
本文探讨了如何利用 Go 语言中的 Bloom Filter 算法提升公司局域网管理系统的性能。Bloom Filter 是一种高效的空间节省型数据结构,适用于快速判断元素是否存在于集合中。文中通过具体代码示例展示了如何在 Go 中实现 Bloom Filter,并应用于局域网的 IP 访问控制,显著提高系统响应速度和安全性。随着网络规模扩大和技术进步,持续优化算法和结合其他安全技术将是企业维持网络竞争力的关键。
17 1
公司局域网管理系统里的 Go 语言 Bloom Filter 算法,太值得深挖了
|
10天前
|
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
62 20
探秘员工泄密行为防线:基于Go语言的布隆过滤器算法解析
在信息爆炸时代,员工泄密行为对企业构成重大威胁。本文聚焦布隆过滤器(Bloom Filter)这一高效数据结构,结合Go语言实现算法,帮助企业识别和预防泄密风险。通过构建正常操作“指纹库”,实时监测员工操作,快速筛查可疑行为。示例代码展示了如何利用布隆过滤器检测异常操作,并提出优化建议,如调整参数、结合日志分析系统等,全方位筑牢企业信息安全防线,守护核心竞争力。
|
16天前
|
Go语言入门:分支结构
本文介绍了Go语言中的条件语句,包括`if...else`、`if...else if`和`switch`结构,并通过多个练习详细解释了它们的用法。`if...else`用于简单的条件判断;`if...else if`处理多条件分支;`switch`则适用于基于不同值的选择逻辑。特别地,文章还介绍了`fallthrough`关键字,用于优化重复代码。通过实例如判断年龄、奇偶数、公交乘车及成绩等级等,帮助读者更好地理解和应用这些结构。
35 14
用 Go 基于 epoll 实现一个最小化的IO库
Go 语言社区中存在多个异步网络框架,如 evio、nbio、gnet 和 netpoll 等。这些框架旨在解决标准库 netpoll 的低效问题,如一个连接占用一个 goroutine 导致的资源浪费。easyio 是一个最小化的 IO 框架,核心代码不超过 500 行,仅实现 Linux 下的 epoll 和 TCP 协议。它通过 Worker Pool、Buffer 等优化提高了性能,并提供了简单的事件处理机制。
|
30天前
|
内网监控系统之 Go 语言布隆过滤器算法深度剖析
在数字化时代,内网监控系统对企业和组织的信息安全至关重要。布隆过滤器(Bloom Filter)作为一种高效的数据结构,能够快速判断元素是否存在于集合中,适用于内网监控中的恶意IP和违规域名筛选。本文介绍其原理、优势及Go语言实现,提升系统性能与响应速度,保障信息安全。
30 5
Go语言中的加密和解密是如何实现的?
Go语言通过标准库中的`crypto`包提供丰富的加密和解密功能,包括对称加密(如AES)、非对称加密(如RSA、ECDSA)及散列函数(如SHA256)。`encoding/base64`包则用于Base64编码与解码。开发者可根据需求选择合适的算法和密钥,使用这些包进行加密操作。示例代码展示了如何使用`crypto/aes`包实现对称加密。加密和解密操作涉及敏感数据处理,需格外注意安全性。
50 14
Go语言中的包(package)是如何组织的?
在Go语言中,包是代码组织和管理的基本单元,用于集合相关函数、类型和变量,便于复用和维护。包通过目录结构、文件命名、初始化函数(`init`)及导出规则来管理命名空间和依赖关系。合理的包组织能提高代码的可读性、可维护性和可复用性,减少耦合度。例如,`stringutils`包提供字符串处理函数,主程序导入使用这些函数,使代码结构清晰易懂。
113 11
Go语言中的map数据结构是如何实现的?
Go 语言中的 `map` 是基于哈希表实现的键值对数据结构,支持快速查找、插入和删除操作。其原理涉及哈希函数、桶(Bucket)、动态扩容和哈希冲突处理等关键机制,平均时间复杂度为 O(1)。为了确保线程安全,Go 提供了 `sync.Map` 类型,通过分段锁实现并发访问的安全性。示例代码展示了如何使用自定义结构体和切片模拟 `map` 功能,以及如何使用 `sync.Map` 进行线程安全的操作。
【01】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-硬件设备实时监控系统运营版发布-本产品基于企业级开源项目Zabbix深度二开-分步骤实现预计10篇合集-自营版
【01】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-硬件设备实时监控系统运营版发布-本产品基于企业级开源项目Zabbix深度二开-分步骤实现预计10篇合集-自营版
25 0

热门文章

最新文章

相关实验场景

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等