Go源码学习:bufio包 - 1.1 - bufio.go -(3)

bufio包官方文档

Go源码学习-索引目录

bufio包学习的上一篇文章:Go源码学习:bufio包 - 1.1 - bufio.go -(2)

17、WriteTo:实现io.WriterTo接口

这部分代码定义了 WriteTo 方法,用于实现 io.WriterTo 接口。该方法可能对底层的 Reader 调用多次 Reader.Read 方法。如果底层读取器支持 Reader.WriteTo 方法,它将直接调用底层的 Reader.WriteTo 而不进行缓冲。

func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
    // 重置上一个字节和上一个rune的大小。
    b.lastByte = -1
    b.lastRuneSize = -1

    // 调用writeBuf将缓冲区中的数据写入目标io.Writer。
    n, err = b.writeBuf(w)
    if err != nil {
        return
    }

    // 如果底层的读取器支持Reader.WriteTo方法,则直接调用它。
    if r, ok := b.rd.(io.WriterTo); ok {
        m, err := r.WriteTo(w)
        n += m
        return n, err
    }

    // 如果目标io.Writer支持io.ReaderFrom方法,则直接调用它。
    if w, ok := w.(io.ReaderFrom); ok {
        m, err := w.ReadFrom(b.rd)
        n += m
        return n, err
    }

    // 如果缓冲区未满,则调用fill方法(缓冲区非满状态)。
    if b.w-b.r < len(b.buf) {
        b.fill() // buffer not full
    }

    // 循环写入数据直到缓冲区为空。
    for b.r < b.w {
        // b.r < b.w => buffer is not empty
        m, err := b.writeBuf(w)
        n += m
        if err != nil {
            return n, err
        }
        b.fill() // buffer is empty
    }

    // 如果错误为io.EOF,则将其重置为nil。
    if b.err == io.EOF {
        b.err = nil
    }

    // 返回写入的总字节数和读取时可能出现的错误。
    return n, b.readErr()
}

解释:

  • WriteTo 方法是 Reader 结构体的方法,实现了 io.WriterTo 接口。
  • 重置了上一个字节和上一个rune的大小。
  • 调用 writeBuf 方法将缓冲区中的数据写入目标 io.Writer
  • 如果底层的读取器支持 Reader.WriteTo 方法,则直接调用它。
  • 如果目标 io.Writer 支持 io.ReaderFrom 方法,则直接调用它。
  • 如果缓冲区未满,则调用 fill 方法(缓冲区非满状态)。
  • 在循环中写入数据直到缓冲区为空,同时调用 writeBuf 方法和 fill 方法。
  • 如果错误为 io.EOF,则将其重置为 nil
  • 返回写入的总字节数和读取时可能出现的错误。

作用:

  • WriteTo 方法实现了 io.WriterTo 接口,允许将缓冲区中的数据写入目标 io.Writer
  • 在写入数据之前,会调用底层的读取器的相关方法,或者通过缓冲区的填充操作来保证有足够的数据可用。
  • 通过多次调用 writeBuf 和可能的底层方法,将数据从读取器传输到目标 io.Writer

18、writeBuf:写入缓冲区

这段代码定义了 writeBuf 方法,用于将 Reader 的缓冲区内容写入到指定的写入器(io.Writer)中。

var errNegativeWrite = errors.New("bufio: writer returned negative count from Write")

// writeBuf 将 Reader 的缓冲区内容写入到写入器中。
func (b *Reader) writeBuf(w io.Writer) (int64, error) {
    // 将缓冲区的内容写入到指定的写入器。
    n, err := w.Write(b.buf[b.r:b.w])
    // 如果写入的字节数 n 小于零,抛出 panic,表示写入返回了负数。
    if n < 0 {
        panic(errNegativeWrite)
    }
    // 将读指针 b.r 向前移动,表示成功写入了 n 个字节。
    b.r += n
    return int64(n), err
}

解释:

  • writeBuf 方法是 Reader 结构体的方法,用于将缓冲区的内容写入到指定的写入器。
  • 它接收一个写入器 w 作为参数,将缓冲区中未读取的数据段写入到该写入器中。
  • 方法返回成功写入的字节数以及可能出现的错误。
  • 在写入过程中,如果写入的字节数 n 小于零,表示写入操作返回了负数,会触发 panic。

作用:

  • writeBuf 方法负责将缓冲区中未读取的数据段写入到指定的写入器中。
  • 它在实现 Reader 结构体的写入操作中发挥着关键作用,将数据从缓冲区传输到目标写入器中。

19、buffered output(缓冲输出)

该部分代码实现了带缓冲的输出,通过 [Writer] 结构体进行缓冲写入。

// Writer 实现了对 io.Writer 对象的缓冲。
// 如果写入 [Writer] 时发生错误,将不再接受更多数据,并且所有后续的写入和 [Writer.Flush] 都将返回错误。
// 在写入所有数据后,客户端应调用 [Writer.Flush] 方法,以确保所有数据已被转发到底层的 [io.Writer]。
type Writer struct {
    err error      // 写入过程中的错误
    buf []byte     // 缓冲区
    n   int        // 缓冲区中已有数据的长度
    wr  io.Writer  // 底层的写入器
}

// NewWriterSize 返回一个新的 [Writer],其缓冲区大小至少为指定大小。
// 如果参数 io.Writer 已经是一个具有足够大大小的 [Writer],它将返回底层的 [Writer]。
func NewWriterSize(w io.Writer, size int) *Writer {
    // 是否已经是一个 Writer?
    b, ok := w.(*Writer)
    if ok && len(b.buf) >= size {
        return b
    }
    if size <= 0 {
        size = defaultBufSize
    }
    return &Writer{
        buf: make([]byte, size),
        wr:  w,
    }
}

// NewWriter 返回一个新的 [Writer],其缓冲区大小为默认大小。
// 如果参数 io.Writer 已经是一个具有足够大缓冲区大小的 [Writer],它将返回底层的 [Writer]。
func NewWriter(w io.Writer) *Writer {
    return NewWriterSize(w, defaultBufSize)
}

解释:

  • Writer 结构体用于实现对 io.Writer 对象的缓冲写入。
  • 结构体字段包括 err(写入过程中的错误)、buf(缓冲区)、n(缓冲区中已有数据的长度)、wr(底层的写入器)。
  • NewWriterSize 方法返回一个新的 Writer,其缓冲区大小至少为指定大小。如果参数 io.Writer 已经是一个具有足够大大小的 Writer,它将返回底层的 Writer
  • NewWriter 方法返回一个新的 Writer,其缓冲区大小为默认大小。如果参数 io.Writer 已经是一个具有足够大缓冲区大小的 Writer,它将返回底层的 Writer

20、Size:获取缓冲区大小

// Size 返回底层缓冲区的大小(以字节为单位)。
func (b *Writer) Size() int { return len(b.buf) }

解释:

  • Size 方法是 Writer 结构体的方法,用于返回该写入器的底层缓冲区的大小。
  • 方法通过返回 len(b.buf),即底层缓冲区 b.buf 的长度(以字节为单位),来表示缓冲区的大小。

作用:

  • Size 方法允许用户查询当前写入器的底层缓冲区大小,以便了解可以容纳的数据量或进行必要的优化。
  • 这个大小值反映了写入器底层缓冲区的实际容量,用于处理写入数据的限制和优化缓冲区大小的相关操作。

21、Reset:重置写入器状态

// Reset 丢弃任何未刷新的缓冲数据,清除任何错误,并将 b 重置为将其输出写入到 w。
// 在零值的 [Writer] 上调用 Reset 会将内部缓冲区初始化为默认大小。
// 调用 w.Reset(w)(即将 [Writer] 重置为自身)不会产生任何效果。
func (b *Writer) Reset(w io.Writer) {
    // 如果一个 Writer w 被传递给 NewWriter,NewWriter 将返回 w。
    // 代码的不同层可能会这样做,然后稍后将 w 传递给 Reset。在这种情况下避免无限递归。
    if b == w {
        return
    }
    if b.buf == nil {
        b.buf = make([]byte, defaultBufSize)
    }
    b.err = nil
    b.n = 0
    b.wr = w
}

解释:

  • Reset 方法是 Writer 结构体的方法,用于重置写入器的状态。
  • 该方法会丢弃任何未刷新的缓冲数据,清除任何错误,并将写入器 b 重置为将其输出写入到指定的写入器 w
  • 如果在零值的 Writer 上调用 Reset,会将内部缓冲区初始化为默认大小。
  • 调用 w.Reset(w)(即将 Writer 重置为自身)不会产生任何效果。

作用:

  • Reset 方法允许用户在不创建新的写入器实例的情况下,重置现有写入器的状态,以便重新使用该写入器。
  • 通过重置写入器,可以清除任何错误状态并将其重新定位到指定的写入器,同时丢弃任何未刷新的缓冲数据。

22、Flush:刷新缓冲区

该部分代码定义了 Flush 方法,用于将任何缓冲的数据写入底层的 [io.Writer]。

// Flush 将任何缓冲的数据写入底层的 [io.Writer]。
func (b *Writer) Flush() error {
    // 如果在写入过程中发生了错误,直接返回错误。
    if b.err != nil {
        return b.err
    }
    // 如果缓冲区中没有数据,直接返回 nil。
    if b.n == 0 {
        return nil
    }
    // 将缓冲区中的数据写入底层的 [io.Writer]。
    n, err := b.wr.Write(b.buf[0:b.n])
    // 如果写入的字节数 n 小于缓冲区中的数据长度 b.n 且没有出现错误,设置错误为 io.ErrShortWrite。
    if n < b.n && err == nil {
        err = io.ErrShortWrite
    }
    // 处理可能出现的错误。
    if err != nil {
        // 如果成功写入了部分数据,将剩余未写入的数据移到缓冲区的开头。
        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
    }
    // 如果写入成功,重置缓冲区中已有数据的长度。
    b.n = 0
    return nil
}

解释:

  • Flush 方法是 Writer 结构体的方法,接收者为 b 结构体。
  • 首先,检查是否在写入过程中发生了错误,如果是,则直接返回错误。
  • 然后,检查缓冲区中是否有数据,如果没有,则直接返回 nil。
  • 接着,将缓冲区中的数据写入底层的 io.Writer
  • 如果写入的字节数 n 小于缓冲区中的数据长度 b.n 且没有出现错误,设置错误为 io.ErrShortWrite
  • 处理可能出现的错误,包括部分写入成功的情况。如果成功写入了部分数据,将剩余未写入的数据移到缓冲区的开头。
  • 更新缓冲区中已有数据的长度。
  • 如果写入过程中发生错误,存储错误并返回。
  • 如果写入成功,重置缓冲区中已有数据的长度。

作用:

  • Flush 方法用于确保将缓冲区中的数据写入底层的 io.Writer
  • 在写入所有数据后,客户端应调用 Flush 方法以确保所有数据已被转发到底层的 io.Writer
  • 如果在写入过程中发生错误,后续的写入和 Flush 将返回相同的错误。

23、Available:获取缓冲区中未使用的字节数

该部分代码定义了 Available 方法,用于返回缓冲区中未使用的字节数。

// Available 返回缓冲区中未使用的字节数。
func (b *Writer) Available() int {
    // 计算并返回缓冲区中未使用的字节数。
    return len(b.buf) - b.n
}

解释:

  • Available 方法是 Writer 结构体的方法,接收者为 b 结构体。
  • 方法直接计算并返回缓冲区中未使用的字节数,即缓冲区总长度减去已使用的字节数。

作用:

  • Available 方法用于获取缓冲区中未使用的字节数。
  • 客户端可以通过调用此方法来了解当前缓冲区中还有多少空间可用于写入数据。

24、AvailableBuffer:获取可用缓冲区

该部分代码定义了 AvailableBuffer 方法,用于获取一个具有可用容量的空缓冲区。

// AvailableBuffer 返回一个空缓冲区,其容量为 b.Available()。
// 此缓冲区用于追加内容,并传递给随后的 [Writer.Write] 调用。
// 缓冲区仅在 b 上的下一次写操作之前有效。
func (b *Writer) AvailableBuffer() []byte {
    return b.buf[b.n:][:0]
}

解释:

  • AvailableBuffer 方法是 Writer 结构体的方法,接收者为 b 结构体。
  • 此方法返回一个空的缓冲区,其容量为 b.Available(),表示可用的写入容量。
  • 返回的缓冲区可以被用于追加内容,并且意图将其传递给接下来的 [Writer.Write] 调用。
  • 注意,该缓冲区仅在下一次对 b 执行写操作之前有效,因为它直接与 b 共享底层的缓冲区。

作用:

  • AvailableBuffer 方法的作用是提供一个可用的空缓冲区,其容量与当前 Writer 结构体中可用的写入容量相匹配。
  • 此缓冲区可以用于填充数据,并传递给后续的写入操作,以最大限度地利用当前缓冲区的剩余空间,提高写入效率。

25、Buffered:获取当前缓冲区中已写入的字节数

该部分代码定义了 Buffered 方法,用于返回当前缓冲区中已写入的字节数。

// Buffered 返回当前缓冲区中已写入的字节数。
func (b *Writer) Buffered() int {
    return b.n
}

解释:

  • Buffered 方法是 Writer 结构体的方法,接收者为 b 结构体。
  • 此方法返回了当前缓冲区中已写入的字节数,即已经占用的写入空间大小。

作用:

  • Buffered 方法用于获取当前缓冲区中已经写入的字节数。
  • 客户端可以通过调用此方法来了解当前缓冲区已被使用了多少空间,以决定是否需要执行刷新操作或其他操作来处理已写入的数据。

26、Write:向缓冲区写入数据

该部分代码定义了 Write 方法,用于将数据写入缓冲区。

// Write 将 p 的内容写入缓冲区。
// 它返回写入的字节数。
// 如果 nn < len(p),它还返回一个解释为什么写入不完整的错误。
func (b *Writer) Write(p []byte) (nn int, err error) {
    for len(p) > b.Available() && b.err == nil {
        var n int
        if b.Buffered() == 0 {
            // 大写入,空缓冲区。
            // 直接从 p 写入,避免复制。
            n, b.err = b.wr.Write(p)
        } else {
            n = copy(b.buf[b.n:], p)
            b.n += n
            b.Flush()
        }
        nn += n
        p = p[n:]
    }
    if b.err != nil {
        return nn, b.err
    }
    n := copy(b.buf[b.n:], p)
    b.n += n
    nn += n
    return nn, nil
}

解释:

  • Write 方法是 Writer 结构体的方法,接收者为 b 结构体。
  • 该方法用于将字节切片 p 的内容写入缓冲区。
  • 如果写入的字节数 nn 小于 p 的长度,它还会返回一个解释为什么写入不完整的错误。
  • 在循环中,当待写入的数据长度大于当前缓冲区的可用空间,并且没有发生错误时,会执行以下操作:
    • 如果缓冲区中没有已写入的数据(b.Buffered() == 0),表示是大写入且缓冲区为空,直接从 p 中写入数据到底层写入源 b.wr,避免复制。
    • 否则,将 p 中的部分数据复制到缓冲区中,并执行 Flush 操作将缓冲区中的数据写入底层写入源 b.wr
    • 更新已写入的字节数 nn,并将 p 中已写入的部分截取掉。
  • 如果在写入过程中发生了错误,直接返回已写入的字节数 nn 和错误信息。
  • 最后,将 p 中剩余的数据复制到缓冲区中,并更新已写入的字节数 nn,然后返回已写入的字节数 nnnil 错误。

作用:

  • Write 方法用于将数据写入缓冲区,并在必要时将缓冲区中的数据刷新到底层的写入源 b.wr 中。
  • 如果待写入的数据长度大于当前缓冲区的可用空间,会根据情况直接写入或者先写入缓冲区再刷新。
  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
回答: 错误提示中提到了一个未知的标志"--go-grpc",这可能是因为你的命令中使用了错误的标志。正确的命令应该是"protoc --go-grpc_out=. --go-grpc_opt=paths=source_relative user.proto"。请注意,标志"--go-grpc_out"和"--go-grpc_opt"之间应该有一个下划线"_",而不是一个空格。另外,你还需要确保你已经安装了正确的go协议编译器插件。你可以使用以下命令重新安装插件:"$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest"和"$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest"。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [使用protoc编译grpc问题记录(--go_out: protoc-gen-go: plugins are not supported;)](https://blog.csdn.net/m0_57777971/article/details/127864341)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [protoc-gen-go: plugin are not supported;use ‘protoc --go-grpc_out=...‘ to generate gRPC 的问题](https://blog.csdn.net/weixin_42875684/article/details/125652895)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风不归Alkaid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值