The case is :
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.