我希望通过尝试再读取一个字节(并捕获EOF)来确认没有更多的字节要从缓冲读取器读取(既不从内部缓冲区读取,也不从底层文件对象读取)。
使用bufio.Read或bufio.ReadByte是否适合此目的?
从bufio.Read文档中尚不清楚在非EOF情况下返回的整数是否可以为零。 即,如果len(p) > 0,0, nil是否是有效的返回值?
func (b *Reader) Read(p []byte) (n int, err error)
Read reads data into p. It returns the number of bytes read into p. The bytes are taken from at most one Read on the underlying Reader, hence n may be less than len(p). To read exactly len(p) bytes, use io.ReadFull(b, p). At EOF, the count will be zero and err will be io.EOF.
同样,bufio.ReadByte文档不能很好地将错误情况与EOF情况分开,并且没有准确定义"可用"(即在内部缓冲区中可用,还是在基础文件中可用)的含义?
func (b *Reader) ReadByte() (byte, error)
ReadByte reads and returns a single byte. If no byte is available, returns an error.
如果读者使用底层os.File作为后盾,将长度为1的缓冲区传递给bufio.Read,则如果文件位于EOF,则确实会返回n==0, io.EOF。
文档有些不精确,因为某些行为取决于您传递给bufio阅读器的基础阅读器。 bufio.Read()的代码绘制了更准确的图片。我将概述逻辑。
bufio.Read:如果内部缓冲区中的所有字节均已用完,则仅向基础读取器发出Read。因此,据推测,如果您已经从缓冲的读取器中读取了与基础文件中的字节数一样多的字节,那么在最后一次调用bufio.Read(buf[0:1])进行EOF检查时,应该耗尽该内部缓冲区。
当内部缓冲区用尽时,如果您要求bufio读取器提供更多信息,则bufio.Read最多将对底层读取器进行一次调用。然后,您得到的错误类型将取决于您的基础读者。
当读取指针已经位于EOF时,要求从os.File读取n > 0字节应返回0, io.EOF(根据os.File File.Read上的文档)。但是,如果您的底层阅读器是其他类型,也许是特定于您的应用程序的自定义类型,该类型旨在在EOF返回0, nil,则bufio.Read会回显它。
bufio.ReadByte:bufio.ReadByte背后的逻辑略有不同,但是在基础阅读器是os.File的情况下,结果应与bufio.Read相同。 bufio.Read的主要区别在于bufio.ReadByte可以多次尝试重新填充内部缓冲区。如果在重新填充过程中遇到错误(在EOF上的os.File读取器就是这种情况),则在第一次错误读取尝试之后将其返回。因此,如果您的基础阅读器是os.File阅读器,则当且仅当您的基础文件位于EOF时,您才会获得0, io.EOF。如果您的基础阅读器是自定义阅读器类型,则仅在EOF返回0, nil,则bufio.ReadByte最终将发出" NoProgress"错误。我不确定为什么重试逻辑仅在bufio.ReadByte中,但是好消息是,如果基础文件的行为类似于os.File,则可以使用这两个选项。
其他资讯:
这不适用于golang,但您可能会发现以下有趣的线程:不在EOF时,read(2)可以返回零字节。它的主题是read()系统调用的语义(POSIX)。在无阻塞套接字/文件上进行读取(即使没有数据准备就绪)也应返回-1,而不是0,并设置errno EAGAIN(或在中断时为EINTR)。非阻塞套接字/文件并不是一个真正的本地化概念(据我所知),尤其是bufio模块将在panic()每当/如果底层阅读器返回负数,那么您就没有了。担心它。