• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    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语言中使用 buffered channel 实现线程安全的 pool
    • C#语言使用gRPC、protobuf(Google Protocol Buffers)实现文件传输功能
    • 详解Django-channels 实现WebSocket实例
    • Django使用Channels实现WebSocket的方法
    • Django Channels 实现点对点实时聊天和消息推送功能
    • 再次探讨go实现无限 buffer 的 channel方法
    上一篇:Go缓冲channel和非缓冲channel的区别说明
    下一篇:go语言-在mac下brew升级golang
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    go原生库的中bytes.Buffer用法 原生,库,的,中,bytes.Buffer,