如何逐行读取文件并返回已读取的字节数?

时间:2014-11-19 12:46:56

标签: go

案例是:

  1. 我想阅读日志,如“tail -f”* NIX
  2. 当我杀死程序时,我可以知道我已经阅读了多少字节,我可以使用seek
  3. 当程序再次启动时,将继续逐行读取日志依赖于步骤2中的搜索数据
  4. 我想在使用bufio.NewScanner作为行阅读器来读取行时获取字节

    例如:

    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! ==================================更新=============== =========================== @twotwotwo这接近我想要的,但我想将 io.Reader 更改为 io.ReaderAt ,这就是我想要的,我写了一个演示使用 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 == '\n' {
                    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)
    
    
        }
    
    }`
    

    这个程序可以告诉我已经读过多少字节,但是无法从我想要的任何地方开始读取,所以我认为如果我们使用 io.ReaderAt 必须可以做到。 再次感谢!

2 个答案:

答案 0 :(得分:0)

您可以考虑另一种基于os.File的方法。

请参阅 ActiveState/tail ,它会监控文件的状态,并使用os.File#Seek()从某一点恢复拖尾文件。

请参阅tail.go

答案 1 :(得分:-1)

考虑构图。

我们知道bufio.NewScanner通过io.Reader接口与其输入进行交互。因此,我们可以使用其他东西来包装io.Reader,以计算到目前为止已读取的字节数。

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\nworld\testing\n")}
    scan := bufio.NewScanner(b)
    for scan.Scan() {
        log.Println(scan.Text())
        log.Println("Read", b.BytesRead, "bytes so far")
    }
}

但是我们会注意到bufio.NewScanner是缓冲的,所以我们可以看到它以块的形式读取它的输入。因此,出于您的目的,这可能没有您想要的那么有用。

另一种方法是取scan.Text()的内容并计算长度。您可以补偿其内部计数中的换行字节的删除。