英文:
Behaviour of io.ReadAt() at the end of input source
问题
我有一个程序,它不断地读取输入文件的字节,以1MB的范围为单位,最初将文件分割为这些范围的倍数,即'n'个窗口范围。源文件的类型是*os.File
,我使用io
包中的ReadAt方法在每个窗口的特定起始地址处进行读取。
问题是,当读取接近文件末尾时,例如在最后一个窗口中,尽管文件仍在范围内,我会收到EOF
错误。当我查阅go.dev文档时,发现它说:
> 如果ReadAt返回的n = len(p)字节位于输入源的末尾,ReadAt可能返回err == EOF或err == nil。
不清楚在什么情况下它会返回nil
,因为即使我仍然在范围内读取,我仍然得到EOF。为什么会发生这种情况,如何避免这种情况?
或者我应该在这种情况下使用io.SectionReader?
对于这种情况,我无法生成一个最小可复现的示例。非常抱歉!
英文:
I have a program that constantly reads bytes of a input file, in 1MB ranges, after initially splitting the file into multiples of this ranges, i.e. 'n' window ranges. The source file is of type *os.File
and I use ReadAt method from the io
package to read at the specific start address of each window.
The problem is, when reading towards the end of the file, e.g. in the last window, though the file is still within the range, I get EOF
errors. When I looked up the go.dev documentation for the same, it says
> If the n = len(p) bytes returned by ReadAt are at the end of the input source, ReadAt may return either err == EOF or err == nil.
It is not clear, under what circumstances it would return nil
, because I keep getting EOF, even when I'm still reading within the range. Why does this happen and how to avoid this situation?
Or I should use io.SectionReader for this case?
Not able to produce a MCVE for this scenario. Apologies!
答案1
得分: 3
如果由ReadAt返回的n = len(p)字节位于输入源的末尾,ReadAt可能返回err == EOF或err == nil。
这段引用与ReaderAt.ReadAt()方法有关:
ReadAt(p []byte, off int64) (n int, err error)
你传递一个要读取的切片和一个要读取的偏移量。该方法返回读取的字节数和一个错误。引用部分的意思是,如果传递的切片已经完全读取,并且此操作耗尽了输入(即到达了末尾),err可能为nil或io.EOF。这取决于具体的实现,你应该编写不依赖于具体实现返回值的代码。
实际上,这意味着如果返回io.EOF,你立即知道没有更多的输入了。如果n == len(p)且err == nil,这只是意味着你还不知道是否还有更多的数据可读,你必须再次调用Read()或ReadAt(),如果没有更多的数据可读,这次将读取0字节(n == 0),而此时err肯定是io.EOF(假设没有其他错误发生)。
ReaderAt.ReadAt()的文档还指出:
当ReadAt返回n < len(p)时,它返回一个非nil的错误,解释为什么没有返回更多的字节。在这方面,ReadAt比Read更严格。
这意味着如果ReadAt()无法从源中完全填充p(例如,因为在读取len(p)字节之前到达了末尾),ReadAt()将返回一个非nil的错误,该错误将是io.EOF(如果原因是到达了源的末尾)。
正如第二个引用所述:ReadAt()比Read()更严格,ReadAt()将尝试填充传递的切片(类似于io.ReadFull())。因此,只有在代码更可读或提供方便的情况下(例如,如果你不想要一个1MB的缓冲区来一次性读取该部分,io.SectionReader可能会使代码更简单),才应该使用io.SectionReader,否则它不会给你带来太多好处。
英文:
> If the n = len(p) bytes returned by ReadAt are at the end of the input source, ReadAt may return either err == EOF or err == nil.
This quote relates to the ReaderAt.ReadAt()
method:
ReadAt(p []byte, off int64) (n int, err error)
You pass a slice to read into, and an offset to read at (from). The method returns the number of read bytes and an error. The quoted part means if the passed slice is fully read and this operation exhausted the input (meaning the end is reached), err
may be nil
or may be io.EOF
. This is implementation dependant, you should write code that does not depend on what a concrete implementation returns.
In practice this means if io.EOF
is returned, you know right away there are no more inputs. If n == len(p)
and err == nil
, this just means you don't know yet whether there are more data to read or not, you have to call Read()
or ReadAt()
again, which will read 0 bytes (n == 0
) if there are no more data, and this time err
will surely be io.EOF
(given no other error occurs).
Documentation of ReaderAt.ReadAt()
also states that:
> When ReadAt returns n < len(p), it returns a non-nil error explaining why more bytes were not returned. In this respect, ReadAt is stricter than Read.
This means if ReadAt()
can't fill p
completely from the source (e.g. because its end is reached before len(p)
bytes could've been read), ReadAt()
will return a non-nil
error which will be io.EOF
(if the cause is that the end of source was reached).
As this second quote states: ReadAt()
is stricter than Read()
, ReadAt()
will try to fill the passed slice (similar to io.ReadFull()
). So you should only use io.SectionReader
if it makes your code more readable or it gives you convenience (e.g. if you do not want a 1 MB buffer to read that part in one step, io.SectionReader
may make that code simpler), otherwise it won't give you much.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论