Golang bufio包源码分析-bufio.Writer

时间:2024-10-26 17:13:31

构造

type Writer struct {
	err error
    // 输出缓冲区
	buf []byte
    // 缓冲区写到哪了
	n   int
    // 被包装的writer
	wr  io.Writer
}

buf是缓冲区,其中buf[0:n]表示装已经写了的数据,buf[n:] 表示还可以写的空间

在这里插入图片描述

Available:缓冲区是否还有剩余空间可写

如果n到最后了,说明没位置可写了

func (b *Writer) Available() int { return len(b.buf) - b.n }

WriteString

整体流程比较直白:

  1. 如果缓冲区够写,就把字符串s写到缓冲区,返回
  2. 否则剩下的缓冲区不够写完整的s,就先写一部分,把缓冲区填满,调Flush方法把缓冲区的全部数据写到真正的writer中
  3. 再把s剩下的部分写到缓冲区中
func (b *Writer) WriteString(s string) (int, error) {
	var sw io.StringWriter
	tryStringWriter := true

	nn := 0

    // 剩余的缓冲区不够写s了
	for len(s) > b.Available() && b.err == nil {
		var n int

        // 先把s的一部分拷贝到buf中
        n = copy(b.buf[b.n:], s)
        b.n += n

        // 调真正的writer把buf的数据写出去
        b.Flush()

		nn += n
        // 扣减本次写过的部分,for循环下次写剩下的部分
		s = s[n:]
	}

    
	if b.err != nil {
		return nn, b.err
	}
    // 到这说明缓存空间还够写s,那就把s完整复制到buf中
	n := copy(b.buf[b.n:], s)
	b.n += n
	nn += n
	return nn, nil
}

Flush

将缓冲区中的所有数据调真正的writer写出去,然后清空缓冲区

func (b *Writer) Flush() error {
	if b.err != nil {
		return b.err
	}
	if b.n == 0 {
		return nil
	}

    // 调真正的writer,写buf中的所有数据
	n, err := b.wr.Write(b.buf[0:b.n])
	if n < b.n && err == nil {
		err = io.ErrShortWrite
	}
	if err != nil {
        // 返回err,但写成功了一部分,写成功的这部分从缓冲区移除
		if n > 0 && n < b.n {
			copy(b.buf[0:b.n-n], b.buf[n:b.n])
		}
		b.n -= n
		b.err = err
		return err
	}

    // 写完后清空buf
	b.n = 0
	return nil
}