4

我目前有这段代码可以逐行读取文件(由 \n 分隔)

file, _ := os.Open(filename) //deal with the error later
defer file.Close()

buf := bufio.NewReader(file)
for line, err := buf.ReadString('\n'); err != io.EOF; line, err = buf.ReadString('\n')
{
    fmt.Println(strings.TrimRight(line, "\n"))
}

但是我对在 for 循环中写两次感到不舒服buf.ReadString("\n"),有没有人有任何改进的建议?

4

2 回答 2

4

bufio.ReadString读取直到输入中第一次出现 delim,返回一个字符串,其中包含直到并包括分隔符的数据。如果 ReadString 在找到分隔符之前遇到错误,它会返回错误之前读取的数据和错误本身(通常是 io.EOF)。当且仅当返回的数据不以 delim 结尾时,ReadString 才会返回 err != nil。

如果buf.ReadString('\n')返回除 以外的错误io.EOF,例如bufio.ErrBufferFull,您将处于无限循环中。此外,如果文件不以 a 结尾'\n',您会默默地忽略最后一个'\n'.

这是一个更强大的解决方案,它执行buf.ReadString('\n')一次。

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "strings"
)

func main() {
    filename := "FileName"
    file, err := os.Open(filename)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer file.Close()
    buf := bufio.NewReader(file)
    for {
        line, err := buf.ReadString('\n')
        if err != nil {
            if err != io.EOF || len(line) > 0 {
                fmt.Println(err)
                return
            }
            break
        }
        fmt.Println(strings.TrimRight(line, "\n"))
    }
}
于 2012-10-11T00:40:08.497 回答
1

大多数逐行读取的代码可以通过不逐行读取来改进。如果您的目标是读取文件并访问这些行,那么以下内容几乎总是更好。

package main

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

func main() {
    b, err := ioutil.ReadFile("filename")
    if err != nil {
        log.Fatal(err)
    }
    s := string(b)                 // convert []byte to string
    s = strings.TrimRight(s, "\n") // strip \n on last line
    ss := strings.Split(s, "\n")   // split to []string
    for _, s := range ss {
        fmt.Println(s)
    }
}

任何错误都会在一个点出现,因此简化了错误处理。正如彼得建议的那样,从最后一行中删除换行符允许文件可能有也可能没有最后的换行符。如今,与可用内存相比,大多数文本文件都很小,因此一口气阅读这些文件是合适的。

于 2012-10-11T13:46:57.723 回答