12

What is the idiomatic way to do a readline to string in Go? the raw functions provided in the standard library seem really low level, they return byte arrays. Is there any built in easier way to get a string out of a readline function?

jz87
  • 9,199
  • 10
  • 37
  • 42
  • 3
    possible duplicate of [reading file line by line in go](http://stackoverflow.com/questions/8757389/reading-file-line-by-line-in-go) – Malcolm Apr 16 '14 at 14:08

3 Answers3

16

I wrote up a way to easily read each line from a file. The Readln(*bufio.Reader) function returns a line (sans \n) from the underlying bufio.Reader struct.

// 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
}

You can use Readln to read every line from a file. The following code reads every line in a file and outputs each line to 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)
}

Cheers!

Malcolm
  • 2,394
  • 1
  • 23
  • 26
  • 4
    this is great but using append is very bad. if you switch that line to copy(ln, line) the function will run about 20 times faster. This was a must for me since I'm parsing files that are many GB. – michael.schuett May 05 '15 at 05:45
  • 5
    @mschuett can you share the modified code with copy? – Viktor Benei Oct 04 '16 at 17:33
14

Here's are some examples using bufio.ReadLine and bufio.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)
}
Matt
  • 22,721
  • 17
  • 71
  • 112
peterSO
  • 158,998
  • 31
  • 281
  • 276
  • Thanks, I was hoping for a more built in way to do this. I'm surprised this functionality is not built in. – jz87 May 28 '11 at 04:04
  • 8
    If you're looking at this today, you'll want to use io.EOF in place of os.EOF. – oleks Jul 16 '12 at 08:44
  • ... and `errors.New(...)` instead of `os.NewError(...)` and `NewReaderSize()` returns only one argument. – topskip Aug 17 '12 at 19:54
  • @jz87the purpose of go is to give you the ability to build tools. If that functionality was built in... also other 3.000.000.000 stuff needed to be there. The point is... if you can build it using go... why it would be there in the first place? – Pedro Luz Apr 06 '16 at 19:29
  • 3
    @PedroLuz by that argument, why don't we all code in assembly? – Emil Jan 30 '19 at 23:46
0

You can also use 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

kubanczyk
  • 5,184
  • 1
  • 41
  • 52
Zombo
  • 1
  • 62
  • 391
  • 407