bufio包学习的上一篇文章:Go源码学习:bufio包 - 1.1 - bufio.go -(3)
27、WriteByte:写入单个字节
这部分代码定义了 WriteByte
方法,用于将单个字节写入缓冲区。
// WriteByte 写入单个字节。
func (b *Writer) WriteByte(c byte) error {
// 如果存在错误,直接返回错误。
if b.err != nil {
return b.err
}
// 如果可用空间不足且刷新操作失败,返回错误。
if b.Available() <= 0 && b.Flush() != nil {
return b.err
}
// 将字节 c 写入缓冲区,并更新写指针 b.n。
b.buf[b.n] = c
b.n++
return nil
}
解释:
WriteByte
方法是Writer
结构体的方法,接收者为指向Writer
结构体的指针b
。- 首先,检查是否存在错误,如果存在直接返回错误。
- 然后,检查缓冲区的可用空间是否足够,以及执行刷新操作是否成功,如果不成功则返回错误。
- 最后,将参数
c
表示的单个字节写入缓冲区,并更新写指针b.n
。
作用:
WriteByte
方法用于将单个字节写入缓冲区,常用于按字节写入数据。- 在写入之前,会进行错误检查,包括缓冲区空间是否足够以及刷新操作的成功与否。
- 写入操作成功后,更新写指针,准备写入下一个字节。
28、WriteRune:写入单个Unicode码点
这部分代码定义了 WriteRune
方法,用于写入单个Unicode码点,返回写入的字节数和任何错误。
// WriteRune 写入单个Unicode码点,返回写入的字节数和任何错误。
func (b *Writer) WriteRune(r rune) (size int, err error) {
// 以uint32比较以正确处理负数的rune。
if uint32(r) < utf8.RuneSelf {
// 如果rune可以用一个字节表示,调用WriteByte写入。
err = b.WriteByte(byte(r))
if err != nil {
return 0, err
}
return 1, nil
}
// 如果存在错误,直接返回错误。
if b.err != nil {
return 0, b.err
}
// 获取可用空间。
n := b.Available()
// 如果可用空间小于utf8.UTFMax,执行刷新操作。
if n < utf8.UTFMax {
if b.Flush(); b.err != nil {
return 0, b.err
}
// 再次获取可用空间,如果仍然小于utf8.UTFMax,调用WriteString写入。
n = b.Available()
if n < utf8.UTFMax {
// 只有在缓冲区非常小的情况下才会发生。
return b.WriteString(string(r))
}
}
// 使用utf8.EncodeRune将rune编码为字节序列,更新写指针。
size = utf8.EncodeRune(b.buf[b.n:], r)
b.n += size
return size, nil
}
解释:
WriteRune
方法是Writer
结构体的方法,接收者为指向Writer
结构体的指针b
。- 首先,检查 Unicode 码点
r
是否可以用一个字节表示,如果是,调用WriteByte
方法直接写入。 - 然后,检查是否存在错误,如果存在直接返回错误。
- 获取缓冲区的可用空间
n
。 - 如果可用空间小于
utf8.UTFMax
,执行刷新操作。 - 再次获取可用空间,如果仍然小于
utf8.UTFMax
,调用WriteString
方法写入字符串形式的 Unicode 码点。 - 最后,使用
utf8.EncodeRune
将 Unicode 码点编码为字节序列,更新写指针。
作用:
WriteRune
方法用于将单个 Unicode 码点写入缓冲区,可以处理多字节的 Unicode 码点。- 在写入之前,会进行一系列的检查和操作,包括判断是否可以用一个字节表示,刷新缓冲区,以及使用
utf8.EncodeRune
进行编码。 - 返回写入的字节数和任何错误。
29、WriteString:写入字符串
这部分代码定义了 WriteString
方法,用于写入字符串。它返回写入的字节数以及可能的错误信息。
// WriteString 写入字符串。
// 返回写入的字节数。
// 如果字节数小于 len(s),还返回一个解释写入为何不完整的错误。
func (b *Writer) WriteString(s string) (int, error) {
var sw io.StringWriter
tryStringWriter := true
nn := 0
for len(s) > b.Available() && b.err == nil {
var n int
if b.Buffered() == 0 && sw == nil && tryStringWriter {
// 仅检查一次 b.wr 是否为 StringWriter。
sw, tryStringWriter = b.wr.(io.StringWriter)
}
if b.Buffered() == 0 && tryStringWriter {
// 大写入、空缓冲区,底层写入器支持 WriteString:
// 将写入转发到底层 StringWriter。
// 这避免了额外的复制。
n, b.err = sw.WriteString(s)
} else {
n = copy(b.buf[b.n:], s)
b.n += n
b.Flush()
}
nn += n
s = s[n:]
}
if b.err != nil {
return nn, b.err
}
n := copy(b.buf[b.n:], s)
b.n += n
nn += n
return nn, nil
}
解释:
WriteString
方法是Writer
结构体的方法,接收者为指向Writer
结构体的指针b
。- 在方法内部,通过循环处理字符串
s
,直到全部写入或者发生错误。 - 在每次迭代中,检查剩余空间是否足够容纳当前字符串,并且没有发生错误。
- 如果缓冲区为空且底层写入器
b.wr
是StringWriter
接口的实现,则尝试将写入操作直接委托给底层的StringWriter
。 - 如果缓冲区不为空,或者无法委托给
StringWriter
,则采用常规的拷贝(copy
)方式将字符串写入缓冲区,并在必要时进行刷新。 - 累计写入的字节数
nn
,并更新字符串s
。 - 最后,如果存在错误,返回累计的字节数和错误;否则,返回累计的字节数和
nil
。
作用:
WriteString
方法用于将字符串写入缓冲区,处理了缓冲区大小不足以容纳整个字符串的情况。- 在写入之前,会尝试将写入操作委托给底层的
StringWriter
接口,以提高效率。 - 返回写入的字节数以及可能的错误信息。
30、ReadFrom:从读取器读取数据
这部分代码定义了 ReadFrom
方法,用于实现 io.ReaderFrom
接口。如果底层写入器支持 ReadFrom
方法,该方法将调用底层的 ReadFrom
方法。如果存在缓冲数据和底层支持 ReadFrom
,则在调用 ReadFrom
之前填充缓冲区并写入数据。
// ReadFrom 实现了 [io.ReaderFrom] 接口。如果底层写入器
// 支持 ReadFrom 方法,此方法将调用底层的 ReadFrom。
// 如果存在缓冲数据和底层支持 ReadFrom,此方法在调用 ReadFrom 之前
// 填充缓冲区并写入数据。
func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
if b.err != nil {
return 0, b.err
}
readerFrom, readerFromOK := b.wr.(io.ReaderFrom)
var m int
for {
if b.Available() == 0 {
if err1 := b.Flush(); err1 != nil {
return n, err1
}
}
if readerFromOK && b.Buffered() == 0 {
nn, err := readerFrom.ReadFrom(r)
b.err = err
n += nn
return n, err
}
nr := 0
for nr < maxConsecutiveEmptyReads {
m, err = r.Read(b.buf[b.n:])
if m != 0 || err != nil {
break
}
nr++
}
if nr == maxConsecutiveEmptyReads {
return n, io.ErrNoProgress
}
b.n += m
n += int64(m)
if err != nil {
break
}
}
if err == io.EOF {
// 如果刚好填满缓冲区,则预先刷新。
if b.Available() == 0 {
err = b.Flush()
} else {
err = nil
}
}
return n, err
}
解释:
ReadFrom
方法是Writer
结构体的方法,接收者为指向Writer
结构体的指针b
。- 在方法内部,首先检查是否存在错误,如果有,直接返回零字节和错误。
- 然后,检查底层写入器
b.wr
是否实现了io.ReaderFrom
接口,以及是否存在底层支持ReadFrom
的情况。 - 在循环中,如果缓冲区可用空间为零,首先尝试刷新缓冲区,以确保有足够的空间用于写入数据。
- 如果底层支持
ReadFrom
且缓冲区为空,直接调用底层的ReadFrom
方法,将读取器r
的数据写入底层写入器,并返回已读取的字节数和错误。 - 如果底层不支持
ReadFrom
或者缓冲区非空,通过循环从读取器r
中读取数据到缓冲区,直到达到最大的连续空读次数。 - 将读取到的数据数量累加到总字节数
n
中,同时更新缓冲区的写指针b.n
。 - 如果发生错误,退出循环。
- 最后,如果错误为
io.EOF
,则在缓冲区刚好填满的情况下提前刷新,以确保所有数据写入。
作用:
ReadFrom
方法用于从一个读取器r
中读取数据,并将其写入底层写入器。- 如果底层支持
ReadFrom
,通过调用底层的ReadFrom
方法实现高效的数据传输。 - 同时,会考虑缓冲区的状态,确保有足够的空间用于写入数据。
31、ReadWriter:带缓冲的输入和输出
这部分代码定义了 ReadWriter
结构体,它包含指向 Reader
和 Writer
的指针,并实现了 io.ReadWriter
接口。
// buffered input and output
// ReadWriter 存储指向 [Reader] 和 [Writer] 的指针。
// 它实现了 [io.ReadWriter] 接口。
type ReadWriter struct {
*Reader
*Writer
}
// NewReadWriter 分配一个新的 [ReadWriter],将其分派给 r 和 w。
func NewReadWriter(r *Reader, w *Writer) *ReadWriter {
return &ReadWriter{r, w}
}
解释:
ReadWriter
是一个结构体,包含了两个指针成员:Reader
和Writer
。这两个指针分别指向Reader
结构体和Writer
结构体。- 结构体实现了
io.ReadWriter
接口,这意味着它可以同时进行读和写操作。 NewReadWriter
函数用于分配并返回一个新的ReadWriter
,该函数接收一个Reader
和一个Writer
,并将它们分别赋值给ReadWriter
结构体的成员。
作用:
ReadWriter
结构体的设计旨在提供带缓冲的输入和输出功能,允许对其进行读取和写入操作。- 通过将
Reader
和Writer
结合在一起,实现了同时进行读和写的能力。 NewReadWriter
函数用于创建一个新的ReadWriter
实例,并将给定的Reader
和Writer
关联到该实例中。