Go readline -> 字符串

12

在Go语言中,如何用惯用方式将readline读取到字符串?标准库提供的原始函数似乎非常低级,它们返回字节数组。是否有任何内置更容易从readline获取字符串的方法?


3
可能是重复问题:在Go中逐行读取文件 - Malcolm
3个回答

16

我写了一个简单的方法来从文件中轻松读取每一行。Readln(*bufio.Reader) 函数可以从底层的 bufio.Reader 结构中返回一行(不包括 \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函数从文件中读取每一行。下面的代码会读取文件中的每一行并将每一行输出到标准输出(stdout)。
f, err := os.Open(fi)
if err != nil {
    fmt.Println("error opening file= ",err)
    os.Exit(1)
}
r := bufio.NewReader(f)
s, e := Readln(r)
for e == nil {
    fmt.Println(s)
    s,e = Readln(r)
}

干杯!


4
这很不错,但使用append非常糟糕。如果您将该行切换为copy(ln, line),则函数的运行速度将快大约20倍。这对我来说是必须的,因为我正在解析许多GB的文件。 - michael.schuett
5
@mschuett,您能分享已修改的代码并复制吗? - Viktor Benei

14

以下是使用bufio.ReadLinebufio.ReadString的示例。

 package main

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

func ReadLine(filename string) {
    f, err := os.Open(filename)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer f.Close()
    r := bufio.NewReaderSize(f, 4*1024)
    line, isPrefix, err := r.ReadLine()
    for err == nil && !isPrefix {
        s := string(line)
        fmt.Println(s)
        line, isPrefix, err = r.ReadLine()
    }
    if isPrefix {
        fmt.Println("buffer size to small")
        return
    }
    if err != io.EOF {
        fmt.Println(err)
        return
    }
}

func ReadString(filename string) {
    f, err := os.Open(filename)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer f.Close()
    r := bufio.NewReader(f)
    line, err := r.ReadString('\n')
    for err == nil {
        fmt.Print(line)
        line, err = r.ReadString('\n')
    }
    if err != io.EOF {
        fmt.Println(err)
        return
    }
}

func main() {
    filename := `testfile`
    ReadLine(filename)
    ReadString(filename)
}

谢谢,我希望有一种更内置的方法来做这件事。我很惊讶这个功能没有内置。 - jz87
8
如果您今天在查看此内容,您需要使用io.EOF来替换os.EOF。 - oleks
...并且使用errors.New(...)代替os.NewError(...),而NewReaderSize()只返回一个参数。 - topskip
@jz87 Go的目的是为了让你有能力构建工具。如果那个功能已经内置了...还有其他30亿个东西需要在那里。重点是...如果你可以使用Go构建它...为什么它一开始就会存在呢? - Pedro Luz
3
按照这个论点,为什么我们不都用汇编语言编程呢? - Emil

0

你也可以使用bufio.NewScanner

package main

import (
   "bufio"
   "os"
)

func main() {
   f, e := os.Open("file.txt")
   if e != nil {
      panic(e)
   }
   defer f.Close()
   s := bufio.NewScanner(f)
   for s.Scan() {
      println(s.Text())
   }
}

https://pkg.go.dev/bufio#Scanner


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接