首页后端开发GOGo 语言标准库 bufio 详解

Go 语言标准库 bufio 详解

时间2023-04-07 17:00:02发布访客分类GO浏览515
导读:01 介绍Go 语言标准库 bufio 是基于 Go 语言标准库 io 实现的,查看源码可以发现,实际上它是包装了 io.Reader 接口和 io.Writer 接口,并且实现它们。bufio 顾名思义,就是在缓冲区读写数据,比直接读写文...

01

介绍

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

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

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

02

标准库 bufio 的数据类型

查看标准库 `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/

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!

go函数数据数据类型源码

若转载请注明出处: Go 语言标准库 bufio 详解
本文地址: https://pptw.com/jishu/2261.html
Go 语言实现创建型设计模式 - 工厂模式 在Golang中常见的7种阻塞使用方式

游客 回复需填写必要信息