从文件读取时如何找到EOF

Posted

技术标签:

【中文标题】从文件读取时如何找到EOF【英文标题】:How to find EOF while reading from a file 【发布时间】: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 文件,调整缓冲区(返回的切片)并要求操作系统完全填充它会更便宜。 【参考方案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

【讨论】:

以上是关于从文件读取时如何找到EOF的主要内容,如果未能解决你的问题,请参考以下文章

C语言从TXT文档中读取一组数字时如何判断已经读到最后一个数字?

如何在 Java 中使用 BufferedReader 读取文件末尾 (EOF)?

关于C语言读取文件结尾的问题

关于EOF和feof()

C语言怎样将数字从文件里逐个读取出来

Python Pandas:标记数据时出错。 C 错误:读取 1GB CSV 文件时字符串中的 EOF 开始