防止ReadFile或ReadAll读取EOF

时间:2016-09-19 07:04:11

标签: go readfile

我开始学习Go,我对使用ioutil.ReadFile函数时包含EOF的事实感到有些困惑。例如,我希望读取一个文件并解析字段分隔符上的所有行。

示例输入文件:

CZG;KCZG;some text
EKY;KEKY;some text
A50;KA50;some text
UKY;UCFL;some text
MIC;KMIC;some text
K2M;K23M;some text

这是我读取和解析该文件的方法:

import(
    "fmt"
    "log"
    "io/ioutil"
    "strings"
    )

func main() {  
    /* Read file */
    airportsFile := "/path/to/file/ad_iata"
    content, err := ioutil.ReadFile(airportsFile)
    if err != nil {
        log.Fatal(err)
    }

    /* split content on EOL */
    lines := strings.Split(string(content), "\n")

    /* split line on field separator ; */
    for _, line := range lines {
        lineSplit := strings.Split(line, ";")
        fmt.Println(lineSplit)
    }
}

string.Split函数在看到EOF(无需解析)时在lineSplit切片的末尾添加一个空元素。因此,如果我想访问该切片的第二个索引(lineSplit[1]),我会遇到panic: runtime error: index out of range。我必须通过这样做来限制范围

/* split line on field separator ; */
lenLines := len(lines) -1
for _, line := range lines[:lenLines] {
    lineSplit := strings.Split(line, ";")
    fmt.Println(lineSplit[1])
}

如果我想继续使用ReadFile来实现它的简洁性,还有更好的方法吗?

使用ioutil.ReadAll

时会出现同样的问题

3 个答案:

答案 0 :(得分:4)

没有“EOF字节”或“EOF字符”这样的东西。您所看到的可能是由文件末尾的换行符('\n')引起的。

要逐行阅读文件,使用bufio.Scanner会更加惯用:

file, err := os.Open(airportsFile)
if err != nil {
    log.Fatal(err)
}
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
    line := scanner.Text()
    // ... use line as you please ...
}

if err := scanner.Err(); err != nil {
    log.Fatal(err)
}

这实际上解决了您的问题,因为Scanner会在不启动新行的情况下读取最终换行符,this playground example可以证明这一点。

答案 1 :(得分:2)

您的输入文件看起来是CSV文件,因此您可以使用encoding/csv

airportsFile := "/path/to/file/ad_iata"
content, err := os.Open(airportsFile)
    if err != nil {
        log.Fatal(err)
    }
r := csv.NewReader(content)
r.Comma = ';'
records, err := r.ReadAll()  /* split line on field separator ; */
if err != nil {
    log.Fatal(err)
}
fmt.Println(records)

看起来足够简洁,并提供正确的输出

<[> [[CZG KCZG一些文字] [EKY KEKY一些文字] [A50 KA50一些文字] [UKY UCFL一些文字] [MIC KMIC一些文字] [K2M K23M一些文字]]

答案 2 :(得分:1)

您可以使用scanner.Err()检查文件读取时的错误。

// Err returns the first non-EOF error that was encountered by the Scanner.
func (s *Scanner) Err() error {
    if s.err == io.EOF {
        return nil
    }
    return s.err
}

一般来说,阅读和解析文件的惯用方法是使用bufio.NewScanner作为输入参数接受要读取的文件并返回新的Scanner

考虑到上述评论,您可以通过以下方式阅读和解析文件:

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    input, err := os.Open("example.txt")

    if err != nil {
        panic("Error happend during opening the file. Please check if file exists!")
        os.Exit(1)
    }

    defer input.Close()

    scanner := bufio.NewScanner(input)
    for scanner.Scan() {
        line := scanner.Text()
        fmt.Printf("%v\n", line)
    }
    if err := scanner.Err(); err != nil {
        fmt.Fprintln(os.Stderr, "reading input:", err)
    }    
}