【问题标题】:How to test EOF on io.Reader in Go?如何在 Go 中的 io.Reader 上测试 EOF?
【发布时间】:2017-05-03 15:57:19
【问题描述】:

Go 的 io.Reader 文档指出,Read() 可能会同时返回非零值 nio.EOF。不幸的是,FileRead() 方法并没有做到这一点。

当到达 EOF 并且仍然可以读取一些字节时,文件的 Read 方法返回非零 nnil 错误。只有当我们已经在文件末尾尝试读取时,我们才会返回零 nio.EOF 作为错误。

如果不尝试从文件中读取数据,我找不到一个简单的方法来测试是否达到 EOF。如果我们使用 0 字节的缓冲区执行 Read(),尽管我们在文件末尾,但我们会返回零 nnil 错误。

为避免最后一次读取,我找到的唯一解决方案是自己跟踪文件中要读取的剩余字节数。有没有更简单的解决方案?

【问题讨论】:

  • 不是 AFAIK。你也许可以使用 seek 或其他东西来获取当前位置,但由于它需要更多的系统调用,所以它会更慢。
  • 为什么不创建一个总是读取一些字节并返回EOF的类型?
  • @JimB 这是一个了不起的技巧。我将采用该解决方案。但我不会提前读取,而是跟踪剩余要读取的字节,以便及时返回 io.EOF。我最喜欢它的原因是我不需要在程序中的任何地方修改代码。我只需要为 File 提供一个包装器。如果你用这两个选项写了一个很好的答案,我会把它授予你。

标签: file go io eof


【解决方案1】:

您可以创建一个新类型,跟踪目前读取的字节数。然后,在 EOF 检查时,您可以将预期读取的字节数与实际读取的字节数进行比较。这是一个示例实现。 eofReader 跟踪读取的字节数并将其与文件大小进行比较,以防底层类型是文件:

package main

// ... imports 

// eofReader can be checked for EOF, without a Read. 
type eofReader struct {
    r     io.Reader
    count uint64
}

// AtEOF returns true, if the number of bytes read equals the file size.
func (r *eofReader) AtEOF() (bool, error) {
    f, ok := r.r.(*os.File)
    if !ok {
        return false, nil
    }
    fi, err := f.Stat()
    if err != nil {
        return false, err
    }
    return r.Count() == uint64(fi.Size()), nil
}

// Read reads and counts.
func (r *eofReader) Read(buf []byte) (int, error) {
    n, err := r.r.Read(buf)
    atomic.AddUint64(&r.count, uint64(n))
    return n, err
}

// Count returns the count.
func (r *eofReader) Count() uint64 {
    return atomic.LoadUint64(&r.count)
}

您可以通过将任何阅读器包装在 eofReader 中来使用此类型:

func main() {
    f, err := os.Open("main.go")
    if err != nil {
        log.Fatal(err)
    }

    r := &eofReader{r: f}
    log.Println(r.AtEOF())

    if _, err = ioutil.ReadAll(r); err != nil {
        log.Fatal(err)
    }

    log.Println(r.AtEOF())
}

// 2016/12/19 03:49:35 false <nil>
// 2016/12/19 03:49:35 true <nil>

代码为gist

【讨论】:

    猜你喜欢
    • 2012-03-27
    • 2020-08-22
    • 1970-01-01
    • 2014-06-05
    • 1970-01-01
    • 2014-12-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-22
    相关资源
    最近更新 更多