go原生库的中bytes.Buffer用法
1 bytes.Buffer定义
bytes.Buffer提供可扩容的字节缓冲区,实质是对切片的封装;结构中包含一个64字节的小切片,避免小内存分配:
// A Buffer is a variable-sized buffer of bytes with Read and Write methods. // The zero value for Buffer is an empty buffer ready to use. type Buffer struct { buf []byte // contents are the bytes buf[off : len(buf)] off int // read at &buf[off], write at &buf[len(buf)]--->指示读指针 bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation. lastRead readOp // last read operation, so that Unread* can work correctly. }
2 初始化bytes.Buffer的方法
1) var buf bytes.Buffer ->定义一个空的字节缓冲区
2) func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} } -->将字节切片初始化为缓冲区
3) func NewBufferString(s string) *Buffer {return &Buffer{buf: []byte(s)}} -->将字符串初始化为缓冲区
3 提供的主要API函数
1)写字节流数据到缓冲区
// Write appends the contents of p to the buffer, growing the buffer as // needed. The return value n is the length of p; err is always nil. If the // buffer becomes too large, Write will panic with ErrTooLarge. func (b *Buffer) Write(p []byte) (n int, err error) { b.lastRead = opInvalid m := b.grow(len(p)) return copy(b.buf[m:], p), nil }
2)写字符串到缓冲区
// WriteString appends the contents of s to the buffer, growing the buffer as // needed. The return value n is the length of s; err is always nil. If the // buffer becomes too large, WriteString will panic with ErrTooLarge. func (b *Buffer) WriteString(s string) (n int, err error) { b.lastRead = opInvalid //返回写入的index m := b.grow(len(s)) return copy(b.buf[m:], s), nil }
3)从缓冲区中读取数据
// Read reads the next len(p) bytes from the buffer or until the buffer // is drained. The return value n is the number of bytes read. If the // buffer has no data to return, err is io.EOF (unless len(p) is zero); // otherwise it is nil. func (b *Buffer) Read(p []byte) (n int, err error) { b.lastRead = opInvalid if b.off >= len(b.buf) { // Buffer is empty, reset to recover space. b.Truncate(0) if len(p) == 0 { return } return 0, io.EOF } n = copy(p, b.buf[b.off:]) b.off += n if n > 0 { b.lastRead = opRead } return }
4)从缓冲区中读取字符串,直到分隔符delim 位置
// ReadString reads until the first occurrence of delim in the input, // returning a string containing the data up to and including the delimiter. // If ReadString encounters an error before finding a delimiter, // it returns the data read before the error and the error itself (often io.EOF). // ReadString returns err != nil if and only if the returned data does not end // in delim. func (b *Buffer) ReadString(delim byte) (line string, err error) { slice, err := b.readSlice(delim) return string(slice), err }
5)将未被读取的字节数据返回
// Bytes returns a slice of length b.Len() holding the unread portion of the buffer. // The slice is valid for use only until the next buffer modification (that is, // only until the next call to a method like Read, Write, Reset, or Truncate). // The slice aliases the buffer content at least until the next buffer modification, // so immediate changes to the slice will affect the result of future reads. func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
6)将未被读取的字节数据以字符串形式返回
// String returns the contents of the unread portion of the buffer // as a string. If the Buffer is a nil pointer, it returns "<nil>". func (b *Buffer) String() string { if b == nil { // Special case, useful in debugging. return "<nil>" } return string(b.buf[b.off:]) }
7)返回缓冲区当前容量
// Cap returns the capacity of the buffer's underlying byte slice, that is, the // total space allocated for the buffer's data. func (b *Buffer) Cap() int { return cap(b.buf) }
8)返回未被读取的字节数据大小
// Len returns the number of bytes of the unread portion of the buffer; // b.Len() == len(b.Bytes()). func (b *Buffer) Len() int { return len(b.buf) - b.off }
4 bytes.Buffer自动扩容机制
当向缓冲区写入数据时,首先会检查当前容量是否满足需求,如果不满足分三种情况处理:
1)当前内置缓冲区切片buf为空,且写入数据量小于bootstrap的大小(64字节),则bootstrap作为buf
2)当前未读数据长度+新写入数据长度小于等于缓冲区容量的1/2,则挪动数据(将未读的数据放到已读数据位置)
3)以上条件不满足,只能重新分配切片,容量设定为2*cap(b.buf) + n,即两倍原来的缓冲区容量+写入数据量大小
// grow grows the buffer to guarantee space for n more bytes. // It returns the index where bytes should be written. // If the buffer can't grow it will panic with ErrTooLarge. func (b *Buffer) grow(n int) int { m := b.Len() // If buffer is empty, reset to recover space. if m == 0 && b.off != 0 { b.Truncate(0) } //如果需要的容量大于现在的容量---> if len(b.buf)+n > cap(b.buf) { var buf []byte //现有的预备64byte可以满足 if b.buf == nil && n <= len(b.bootstrap) { buf = b.bootstrap[0:] //实际需要的小于本身切片容量 } else if m+n <= cap(b.buf)/2 { // We can slide things down instead of allocating a new // slice. We only need m+n <= cap(b.buf) to slide, but // we instead let capacity get twice as large so we // don't spend all our time copying. copy(b.buf[:], b.buf[b.off:]) buf = b.buf[:m] } else { // not enough space anywhere //不够,那就分配2倍加n的容量 buf = makeSlice(2*cap(b.buf) + n) copy(buf, b.buf[b.off:]) } b.buf = buf b.off = 0 } b.buf = b.buf[0 : b.off+m+n] return b.off + m }
5 bytes.Buffer的局限
bytes.Buffer提供了对切片的初步封装,但也没做太多的事;对于已读的数据无法操作。
补充:Golang bytes.Buffer 用法精述
1.简介
bytes.Buffer 是 Golang 标准库中的缓冲区,具有读写方法和可变大小的字节存储功能。缓冲区的零值是一个待使用的空缓冲区。
定义如下:
type Buffer struct { buf []byte // contents are the bytes buf[off : len(buf)] off int // read at &buf[off], write at &buf[len(buf)] lastRead readOp // last read operation, so that Unread* can work correctly. }
注意要点:
(1)从 bytes.Buffer 读取数据后,被成功读取的数据仍保留在原缓冲区,只是无法被使用,因为缓冲区的可见数据从偏移 off 开始,即buf[off : len(buf)]。
2.常用方法
(1)声明一个 Buffer
var b bytes.Buffer //直接定义一个Buffer变量,不用初始化,可以直接使用 b := new(bytes.Buffer) //使用New返回Buffer变量 b := bytes.NewBuffer(s []byte) //从一个[]byte切片,构造一个Buffer b := bytes.NewBufferString(s string) //从一个string变量,构造一个Buffer
(2)往 Buffer 中写入数据
b.Write(d []byte) (n int, err error) //将切片d写入Buffer尾部 b.WriteString(s string) (n int, err error) //将字符串s写入Buffer尾部 b.WriteByte(c byte) error //将字符c写入Buffer尾部 b.WriteRune(r rune) (n int, err error) //将一个rune类型的数据放到缓冲区的尾部 b.ReadFrom(r io.Reader) (n int64, err error) //从实现了io.Reader接口的可读取对象写入Buffer尾部
(3)从 Buffer 中读取数据
//读取 n 个字节数据并返回,如果 buffer 不足 n 字节,则读取全部 b.Next(n int) []byte //一次读取 len(p) 个 byte 到 p 中,每次读取新的内容将覆盖p中原来的内容。成功返回实际读取的字节数,off 向后偏移 n,buffer 没有数据返回错误 io.EOF b.Read(p []byte) (n int, err error) //读取第一个byte并返回,off 向后偏移 n b.ReadByte() (byte, error) //读取第一个 UTF8 编码的字符并返回该字符和该字符的字节数,b的第1个rune被拿掉。如果buffer为空,返回错误 io.EOF,如果不是UTF8编码的字符,则消费一个字节,返回 (U+FFFD,1,nil) b.ReadRune() (r rune, size int, err error) //读取缓冲区第一个分隔符前面的内容以及分隔符并返回,缓冲区会清空读取的内容。如果没有发现分隔符,则返回读取的内容并返回错误io.EOF b.ReadBytes(delimiter byte) (line []byte, err error) //读取缓冲区第一个分隔符前面的内容以及分隔符并作为字符串返回,缓冲区会清空读取的内容。如果没有发现分隔符,则返回读取的内容并返回错误 io.EOF b.ReadString(delimiter byte) (line string, err error) //将 Buffer 中的内容输出到实现了 io.Writer 接口的可写入对象中,成功返回写入的字节数,失败返回错误 b.WriteTo(w io.Writer) (n int64, err error)
(4)其它操作
b.Bytes() []byte //返回字节切片 b.Cap() int //返回 buffer 内部字节切片的容量 b.Grow(n int) //为 buffer 内部字节切片的容量增加 n 字节 b.Len() int //返回缓冲区数据长度,等于 len(b.Bytes()) b.Reset() //清空数据 b.String() string //字符串化 b.Truncate(n int) //丢弃缓冲区中除前n个未读字节以外的所有字节。如果 n 为负数或大于缓冲区长度,则引发 panic b.UnreadByte() error //将最后一次读取操作中被成功读取的字节设为未被读取的状态,即将已读取的偏移 off 减 1 b.UnreadRune() error //将最后一次 ReadRune() 读取操作返回的 UTF8 字符 rune设为未被读取的状态,即将已读取的偏移 off 减去 字符 rune 的字节数
3.使用示例
(1)从文件 test.txt 中读取全部内容追加到 buffer 尾部
test.txt 的内容为:
My name is dablelv
具体实现:
package main import ( "os" "fmt" "bytes" ) func main() { file, _ := os.Open("./test.txt") buf := bytes.NewBufferString("Hello world ") buf.ReadFrom(file) //将text.txt内容追加到缓冲器的尾部 fmt.Println(buf.String()) }
编译运行输出:
Hello world My name is dablelv
以上为个人经验,希望能给大家一个参考,也希望大家多多支持猪先飞。如有错误或未考虑完全的地方,望不吝赐教。
相关文章
- 在程序员中,尤其是go新手,经常听到的一个讨论话题是:如何处理错误,这篇文章主要给大家介绍了关于Go应用中优雅处理Error的一些相关技巧,需要的朋友可以参考下...2021-09-08
Django def clean()函数对表单中的数据进行验证操作
这篇文章主要介绍了Django def clean()函数对表单中的数据进行验证操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-09- 这篇文章主要介绍了golang官方嵌入文件到可执行程序,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-20
- 这篇文章主要介绍了go浮点数转字符串保留小数点后N位解决办法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-05-11
- 这篇文章主要介绍了Go语言使用读写OPC详解,图文讲解的很清晰,有感兴趣的同学可以学习下...2021-03-05
- 这篇文章主要介绍了Go项目的目录结构,对基础目录做了讲解,对项目开发中的其它目录也一并做了介绍,需要的朋友可以参考下...2020-05-01
- string与[]byte经常需要互相转化,普通转化会发生底层数据的复制,下面这篇文章主要给大家介绍了关于Go中string与[]byte高效互转的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下...2021-09-20
- Go 语言提供的基础容器,免不了要查询容器中的数据,那么是如何实现遍历的呢?本文将会介绍几种常用容易的遍历及其使用。感兴趣的可以了解一下...2021-06-13
- 这篇文章主要介绍了创建第一个Go语言程序Hello,Go!本文详细的给出项目创建、代码编写的过程,同时讲解了GOPATH、Go install等内容,需要的朋友可以参考下...2020-05-01
- 这篇文章主要介绍了在Django中使用MQTT的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-05-10
- 这篇文章主要介绍了go语言中的Carbon库时间处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-05
- 这篇文章主要介绍了go嵌套匿名结构体的初始化详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-16
解决导入django_filters不成功问题No module named 'django_filter'
这篇文章主要介绍了解决导入django_filters不成功问题No module named 'django_filter',具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-15- 本文主要介绍了Django项目连接MongoDB的三种方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-27
详解如何使用Docker部署Django+MySQL8开发环境
这篇文章主要介绍了详解如何使用Docker部署Django+MySQL8开发环境,文中通过示例代码以及图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧...2020-07-19- 这篇文章主要介绍了Go语言json编码驼峰转下划线、下划线转驼峰的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-09
- 这篇文章主要介绍了Django 解决由save方法引发的错误,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-05-21
- 这篇文章主要介绍了django前端页面下拉选择框默认值设置方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-10
- 这篇文章主要介绍了django数据模型中null和blank的区别说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-03
- 这篇文章主要介绍了Go 自定义package包设置与导入操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-05-06