我希望通过尝试再读取一个字节(并捕获EOF)来确认没有更多的字节要从缓冲读取器读取(既不从内部缓冲区读取,也不从底层文件对象读取)。
为此使用bufio.Read
或bufio.ReadByte
吗?
从bufio.Read
documentation尚不清楚在非EOF情况下返回的整数是否可以为零。即,如果0, nil
,len(p) > 0
是有效的返回值吗?
类似地,bufio.ReadByte
文档没有很好地将错误情况与EOF情况分开,并且没有确切定义“可用”(即在内部缓冲区中可用,还是在基础文件中可用)的含义?
最佳答案
当读者获得底层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上时,要求从n > 0
中读取os.File
字节应返回0, io.EOF
(根据 os.File File.Read
上的文档)。但是,如果您的底层阅读器是别的东西,也许是特定于您的应用程序的自定义类型,旨在在EOF返回0, nil
,则bufio.Read
会回显该内容。
bufio.ReadByte
: bufio.ReadByte
背后的逻辑略有不同,但是如果基础阅读器是bufio.Read
,则结果应与os.File
相同。 bufio.Read
的主要区别在于bufio.ReadByte
可以尝试多次填充内部缓冲区。如果在重新填充过程中遇到错误(EOF上的os.File
阅读器就是这种情况),则在第一次错误读取尝试后将其返回。因此,如果您的基础阅读器是os.File
阅读器,那么当且仅当您的基础文件位于EOF时,您才会获得0, io.EOF
。如果您的基础阅读器是仅在EOF返回0, nil
的自定义阅读器类型,则bufio.ReadByte
最终将发出“NoProgress”错误。我不确定为什么重试逻辑仅在bufio.ReadByte
中,但是好消息是,如果基础文件的行为类似于os.File
,则可以使用这两个选项。
其他信息:
这不适用于golang,但您可能会发现以下有趣的线程:Can read(2) return zero bytes when not at EOF。它的主题是read()系统调用的语义(POSIX)。在无阻塞套接字/文件上进行读取(即使没有数据准备就绪)也应返回-1,而不是0,并设置errno EAGAIN(或在中断时为EINTR)。无阻塞套接字/文件并不是一个真正的本地化概念(据我所知),尤其是当底层读者返回负数时,bufio
模块将特别是panic()
,因此您不必担心它。
关于go - golang bufio.Read或bufio.ReadByte来检测文件是否位于EOF,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55388581/