【问题标题】:How to find EOF while reading from a file从文件读取时如何找到EOF
【发布时间】:2013-01-06 07:55:14
【问题描述】:

我正在使用以下代码在 Go 中读取文件:

spoon , err := ioutil.ReadFile(os.Args[1])
if err!=nil {
        panic ("File reading error")
}

现在我检查我选择的每个字节是什么字符。例如:

spoon[i]==' ' //for checking space

同样,我阅读了整个文件(我知道可能还有其他阅读方式) 但是保持这种方式不变,我怎么知道我已经达到了文件的 EOF 并且我应该停止进一步阅读它?

请不要建议找到spoon的长度并开始循环。我想要找到 EOF 的可靠方法。

【问题讨论】:

  • 简单的解决方案:单片眼镜!
  • @thang 什么是单片眼镜?
  • @Worlock:再一次,上面显示的问题不直接涉及任何EOF。它可能从返回的spoon 切片中的字节数推断出来,如果按顺序读取文件,则会出现io.EOF。即使io.ReadFile 可能从未在此设置中看到任何 EOF。 stat 文件,调整缓冲区(返回的切片)并要求操作系统完全填充它会更便宜。

标签: go file-handling


【解决方案1】:

使用io.EOF 测试文件结束。例如,要计算文件中的空格数:

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    if len(os.Args) <= 1 {
        fmt.Println("Missing file name argument")
        return
    }
    f, err := os.Open(os.Args[1])
    if err != nil {
        fmt.Println(err)
        return
    }
    defer f.Close()
    data := make([]byte, 100)
    spaces := 0
    for {
        data = data[:cap(data)]
        n, err := f.Read(data)
        if err != nil {
            if err == io.EOF {
                break
            }
            fmt.Println(err)
            return
        }
        data = data[:n]
        for _, b := range data {
            if b == ' ' {
                spaces++
            }
        }
    }
    fmt.Println(spaces)
}

【讨论】:

  • Read 可以在 EOF 旁边返回数据:“调用方应始终处理返回的 n > 0 字节,然后再考虑错误错误。这样做可以正确处理读取某些字节后发生的 I/O 错误,以及两者允许的 EOF 行为。”
【解决方案2】:

ioutil.ReadFile() 将文件的全部内容读入一个字节片。您无需担心 EOF。 EOF 是一次读取一个文件时需要的一种结构。当您一次读取一个块时,您需要知道哪个块已到达文件末尾。

ioutil.ReadFile() 返回的字节片的长度就是你所需要的。

data := ioutil.ReadFile(os.Args[1])

// Do we need to know the data size?
slice_size := len(data)

// Do we need to look at each byte?
for _,byte := range data {
    // do something with each byte
}

【讨论】:

  • 您写道“您需要知道哪个块已到达文件末尾”。我怎么知道?顺便说一句你写的?还是总结不同?
【解决方案3】:

这是您需要查找的有关文件结尾(EOF)的信息

if err != nil {
        if errors.Is(err, io.EOF) { // prefered way by GoLang doc
            fmt.Println("Reading file finished...")
        }
        break
    }

【讨论】:

    【解决方案4】:

    当您使用ioutil.ReadFile() 时,您永远不会看到 io.EOF,因为 ReadFile 将读取整个文件,直到到达 EOF。所以它返回的切片整个文件。来自文档:

    ReadFile 读取以 filename 命名的文件并返回内容。成功的调用返回 err == nil,而不是 err == EOF。因为 ReadFile 读取整个文件,所以它不会将 Read 中的 EOF 视为要报告的错误。

    从您的问题中,您明确提到您知道还有其他方法可以读取文件,其中一些方法需要您测试 io.EOF 的错误,而不是 ReadFile。

    然后,使用您拥有的切片,您可以使用 for...range 构造读取文件,正如其他人提到的那样。这是一种确定读取整个文件的方式,仅此而已(同样,ReadFile 负责处理)。或者从 0 迭代到 len(spoon) - 1 也可以,但是 range 更惯用,基本上也是一样的。

    换句话说:当您到达切片的末尾时,您就到达了文件的末尾(前提是 ReadFile 没有返回错误)。

    【讨论】:

      【解决方案5】:

      切片没有文件结尾的概念。 ioutil.ReadFile 返回的切片有一个特定的长度,它反映了读取它的文件的大小。一个常见的习惯用法,但只是在这种情况下使用的一种可能,是对切片进行范围,有效地“消耗”最初位于文件中的所有字节:

      for i, b := range spoon {
              // At index 'i' is byte 'b'
              // At file's offset 'i', 'b' was read
              ... do something useful here
      }
      

      【讨论】:

        猜你喜欢
        • 2015-06-21
        • 1970-01-01
        • 2020-07-19
        • 1970-01-01
        • 2017-04-27
        • 1970-01-01
        • 1970-01-01
        • 2020-10-24
        • 2010-09-17
        相关资源
        最近更新 更多