如何逐行读取文件并返回已读取多少字节?

The case is :

  1. I want read the log like "tail -f" *NIX
  2. when I kill the program I can know how many bytes I have already read,and I can use the seek
  3. when the program start again,will continue to read the log line by line depend by seek data in step 2

I want get the bytes when I use bufio.NewScanner as a line reader to read a line

eg:

import ...
func main() {
    f, err := os.Open("111.txt") 
    if err != nil {          
        log.Fatal(err)
    }
    f.Seek(0,os.SEEK_SET)
    scan := bufio.NewScanner(f)
    for scan.Scan() {
        log.Printf(scan.Text())
        //what I want is how many bytes at this time when I read a line
    }//This is a program for read line

}

thx! ==================================update========================================== @twotwotwo this is close to what I want,but I want change the io.Reader to the io.ReaderAt, and it is what I want,I write a demo use the io.Reader:`

import (
   "os"
   "log"
   "io"
)
type Reader struct {
    reader io.Reader
    count  int
}
func (r *Reader) Read(b []byte) (int, error) {
    n, err := r.reader.Read(b)
    r.count += n
    return n, err
}
func (r *Reader) Count() int {
    return r.count
}
func NewReader(r io.Reader) *Reader {
    return &Reader{reader: r}
}

func ReadLine(r *Reader) (ln int,line []byte,err error) {
    line = make([]byte,0,4096)
    for {
        b := make([]byte,1)
        n,er := r.Read(b)
        if er == io.EOF {
            err = er
            break
        }
        if n > 0{
            c := b[0]
            if c == '
' {
                break
            }
            line = append(line, c)
        }
        if er != nil{
            err = er
        }
    }

    ln = r.Count()
    return ln,line,err
}

func main() {
    f, err := os.Open("111.txt")
    if err != nil {          
        log.Fatal(err)
    }
    fi,_:=os.Stat("111.txt")
    log.Printf("the file have %v bytes",fi.Size())
    co := NewReader(f)
    for {
        count,line,er := ReadLine(co)
        if er == io.EOF {
            break
        }
        log.Printf("now read the line :%v",string(line))
        log.Printf("in all we have read %v bytes",count)


    }

}`

this Program can tell me how many bytes I have already read,but cannt read start from anywhere where I want,so I think that if we use io.ReaderAt must can do it. thanks again!

You could consider another approach based on os.File.

See ActiveState/tail, which monitor the state of a file, and uses os.File#Seek() to resume tailing a file from within a certain point.

See tail.go.

Consider composition.

We know that bufio.NewScanner is interacting with its input through the io.Reader interface. So we may wrap an io.Reader with something else that counts how many bytes have been read so far.

package main

import (
    "bufio"
    "bytes"
    "io"
    "log"
)

type ReadCounter struct {
    io.Reader
    BytesRead int
}

func (r *ReadCounter) Read(p []byte) (int, error) {
    n, err := r.Reader.Read(p)
    r.BytesRead += n
    return n, err
}

func main() {
    b := &ReadCounter{Reader: bytes.NewBufferString("hello
world\testing
")}
    scan := bufio.NewScanner(b)
    for scan.Scan() {
        log.Println(scan.Text())
        log.Println("Read", b.BytesRead, "bytes so far")
    }
}

But we'll note that bufio.NewScanner is buffered, so we can see that it reads its input in chunks. So for your purposes, this might not be as useful as you want.

An alternative is to take the content of scan.Text() and count up the lengths. You can compensate for its removal of newline bytes in your internal count.