我找不到文件。围棋中的ReadLine函数。

如何一行一行地读取文件?


当前回答

在Go 1.1和更新版本中,最简单的方法是使用bufio.Scanner。下面是一个简单的例子,从文件中读取行:

package main

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

func main() {
    file, err := os.Open("/path/to/file.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    scanner := bufio.NewScanner(file)
    // optionally, resize scanner's capacity for lines over 64K, see next example
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }

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

这是从Reader中逐行读取的最干净的方法。

这里有一个警告:当行长度超过65536个字符时,Scanner将出错。如果你知道你的行长大于64K,使用Buffer()方法来增加扫描仪的容量:

...
scanner := bufio.NewScanner(file)

const maxCapacity int = longLineLen  // your required line length
buf := make([]byte, maxCapacity)
scanner.Buffer(buf, maxCapacity)

for scanner.Scan() {
...

其他回答

注意:在Go的早期版本中,接受的答案是正确的。见投票最高的答案包含了实现这一目标的最新惯用方法。

包bufio中有一个ReadLine函数。

请注意,如果该行不适合读缓冲区,该函数将返回一个不完整的行。如果你想通过对函数的一次调用来读取程序中的整行,你需要将ReadLine函数封装到你自己的函数中,该函数在for循环中调用ReadLine。

bufio.ReadString('\n')并不完全等同于ReadLine,因为ReadString无法处理文件的最后一行不以换行符结束的情况。

有两种常见的逐行读取文件的方法。

使用bufio。扫描仪 使用ReadString / ReadBytes /……在bufio。读者

在我的测试案例中,~250MB, ~2,500,000行,bufio。Scanner(使用时间:0.395491384s)比bufio.Reader快。ReadString (time_used: 0.446867622 s)。

源代码:https://github.com/xpzouying/go-practice/tree/master/read_file_line_by_line

使用bufio读取文件。扫描仪,

func scanFile() {
    f, err := os.OpenFile(logfile, os.O_RDONLY, os.ModePerm)
    if err != nil {
        log.Fatalf("open file error: %v", err)
        return
    }
    defer f.Close()

    sc := bufio.NewScanner(f)
    for sc.Scan() {
        _ = sc.Text()  // GET the line string
    }
    if err := sc.Err(); err != nil {
        log.Fatalf("scan file error: %v", err)
        return
    }
}

使用bufio读取文件。读者,

func readFileLines() {
    f, err := os.OpenFile(logfile, os.O_RDONLY, os.ModePerm)
    if err != nil {
        log.Fatalf("open file error: %v", err)
        return
    }
    defer f.Close()

    rd := bufio.NewReader(f)
    for {
        line, err := rd.ReadString('\n')
        if err != nil {
            if err == io.EOF {
                break
            }

            log.Fatalf("read file line error: %v", err)
            return
        }
        _ = line  // GET the line string
    }
}

另一种方法是使用io/ioutil和strings库来读取整个文件的字节,将它们转换为字符串,并使用“\n”(换行符)字符作为分隔符来分割它们,例如:

import (
    "io/ioutil"
    "strings"
)

func main() {
    bytesRead, _ := ioutil.ReadFile("something.txt")
    fileContent := string(bytesRead)
    lines := strings.Split(fileContent, "\n")
}

从技术上讲,您不是逐行读取文件,但是您可以使用这种技术解析每一行。此方法适用于较小的文件。如果您试图解析一个大型文件,请使用逐行读取的技术之一。

编辑:从go1.1开始,惯用的解决方案是使用bufio。扫描仪

我写了一种从文件中轻松读取每一行的方法。Readln(*bufio. reader)函数的作用是:从底层bufio返回一行(sans \n)。读者结构。

// Readln returns a single line (without the ending \n)
// from the input buffered reader.
// An error is returned iff there is an error with the
// buffered reader.
func Readln(r *bufio.Reader) (string, error) {
  var (isPrefix bool = true
       err error = nil
       line, ln []byte
      )
  for isPrefix && err == nil {
      line, isPrefix, err = r.ReadLine()
      ln = append(ln, line...)
  }
  return string(ln),err
}

您可以使用Readln从文件中读取每一行。下面的代码读取文件中的每一行,并将每一行输出到标准输出。

f, err := os.Open(fi)
if err != nil {
    fmt.Printf("error opening file: %v\n",err)
    os.Exit(1)
}
r := bufio.NewReader(f)
s, e := Readln(r)
for e == nil {
    fmt.Println(s)
    s,e = Readln(r)
}

干杯!

bufio.Reader.ReadLine()工作得很好。但是如果你想通过字符串读取每一行,尝试使用ReadString('\n')。它不需要重新发明轮子。