我希望通过尝试再读取一个字节(并捕获EOF)来确认没有更多的字节要从缓冲读取器读取(既不是从内部缓冲区读取,也不是从底层文件对象读取)。
是否为此目的使用bufio.Read
或bufio.ReadByte
?
在非EOF情况下,从bufio.Read
documentation尚不清楚返回的整数是否可以为零。也就是说,如果0, nil
是len(p) > 0
的有效返回值?
func (b *Reader) Read(p []byte) (n int, err error)
Read将数据读入p。它返回读入p的字节数。这些字节是从基础读取器上的最多一个读取中获取的,因此n可能小于len(p)。要精确读取len(p)个字节,请使用io.ReadFull(b,p)。在EOF时,计数将为零,而err将为io.EOF。
类似地,bufio.ReadByte
文档没有很好地将错误情况与EOF情况分开,并且它也没有完全定义“可用”(即内部缓冲区中可用,或基础文件)?
func (b *Reader) ReadByte() (byte, error)
ReadByte读取并返回一个字节。如果没有可用的字节,则返回错误。
答案 0 :(得分:3)
如果读取器得到底层os.File 的支持,则将长度为1的缓冲区传递给bufio.Read
,如果文件位于EOF,则确实会返回n==0, io.EOF
。
由于某些行为取决于您传递给bufio
阅读器的基础阅读器,因此该文档有点不精确。 bufio.Read()
的代码可以绘制出更准确的图片。我将概述逻辑。
bufio.Read
::仅当内部缓冲区中的所有字节都用完时,才向基础读取器发出Read
。因此,据推测,如果您已经从缓冲的读取器中读取了与基础文件中的字节数一样多的字节,那么在您进行最后一次调用bufio.Read(buf[0:1])
来检查EOF时,应该耗尽该内部缓冲区。 / p>
内部缓冲区用完后,如果您要求bufio
阅读器提供更多信息,bufio.Read
将最多对底层阅读器进行一次调用。然后,您得到的错误类型将取决于您的基础读者。
当读取指针已经位于EOF时,要求从n > 0
读取os.File
个字节(应根据os.File File.Read
上的文档)返回0, io.EOF
。但是,如果您的底层阅读器是其他类型,也许是特定于您的应用程序的自定义类型,该类型旨在在EOF返回0, nil
,则bufio.Read
会回显它。
bufio.ReadByte
:bufio.ReadByte
背后的逻辑略有不同,但是在基础读者是{{的情况下,结果应与bufio.Read
相同。 1}}。 os.File
的主要区别在于bufio.Read
可以尝试多次填充内部缓冲区。如果在重新填充过程中遇到错误(在EOF上的bufio.ReadByte
阅读器会遇到这种情况),则在第一次错误的读取尝试之后将其返回。因此,如果您的基础阅读器是os.File
阅读器,那么当且仅当您的基础文件位于EOF时,您会得到os.File
。如果您的基础阅读器是自定义阅读器类型,则只在EOF返回0, io.EOF
,则0, nil
最终将发出“ NoProgress”错误。我不确定为什么重试逻辑仅在bufio.ReadByte
中出现,但是好消息是,如果基础文件的行为类似于bufio.ReadByte
,则可以使用这两个选项。
其他信息:
这不适用于golang,但是您可能会发现以下有趣的线程:Can read(2) return zero bytes when not at EOF。它的主题是read()系统调用的语义(POSIX)。在无阻塞套接字/文件上进行读取,即使没有数据就绪也应返回-1,而不是0,并设置errno EAGAIN(或在中断时为EINTR)。无阻塞套接字/文件并不是一个真正的本地化概念(据我所知),尤其是os.File
模块将在{/ 1}只要底层读者返回负数的情况下就会bufio
,因此您不必担心。