Use bufio.Scanner.
For example,
package main
import (
"bufio"
"bytes"
"fmt"
"os"
)
func dropCRLF(data []byte) []byte {
if len(data) > 0 && data[len(data)-1] == '\n' {
data = data[0 : len(data)-1]
if len(data) > 0 && data[len(data)-1] == '\r' {
data = data[0 : len(data)-1]
}
}
return data
}
// Adaptation of bufio.ScanLines that returns end-of-line carriage returns and line feeds.
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
if i := bytes.IndexByte(data, '\n'); i >= 0 {
// We have a full newline-terminated line.
return i + 1, data[0 : i+1], nil
}
// If we're at EOF, we have a final, non-terminated line. Return it.
if atEOF {
return len(data), data, nil
}
// Request more data.
return 0, nil, nil
}
func main() {
f, err := os.Open("lines.txt")
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
defer f.Close()
scanner := bufio.NewScanner(f)
scanner.Split(ScanLines)
n := int64(0)
for scanner.Scan() {
b := scanner.Bytes()
eol := n
n += int64(len(b))
b = dropCRLF(b)
eol += int64(len(b))
fmt.Printf("%s : %d\n", b, eol)
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
Input (lines.txt):
Output:
line 1 : 6
line 2 : 13
line 3 : 20