“tail -f”-like generator

后端 未结 2 1605
伪装坚强ぢ
伪装坚强ぢ 2021-01-11 19:42

I had this convenient function in Python:

def follow(path):
    with open(self.path) as lines:
        lines.seek(0, 2)  # seek to EOF

        while True:
          


        
相关标签:
2条回答
  • 2021-01-11 20:05

    I suggest creating a wrapper around a reader that sleeps on EOF:

    type tailReader struct {
        io.ReadCloser
    }
    
    func (t tailReader) Read(b []byte) (int, error) {
        for {
            n, err := t.ReadCloser.Read(b)
            if n > 0 {
                return n, nil
            } else if err != io.EOF {
                return n, err
            }
            time.Sleep(10 * time.Millisecond)
        }
    }
    
    func newTailReader(fileName string) (tailReader, error) {
        f, err := os.Open(fileName)
        if err != nil {
            return tailReader{}, err
        }
    
        if _, err := f.Seek(0, 2); err != nil {
            return tailReader{}, err
        }
        return tailReader{f}, nil
    }
    

    This reader can be used anywhere an io.Reader can be used. Here's how loop over lines using bufio.Scanner:

    t, err := newTailReader("somefile")
    if err != nil {
        log.Fatal(err)
    }
    defer t.Close()
    scanner := bufio.NewScanner(t)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        fmt.Fprintln(os.Stderr, "reading:", err)
    }
    

    The reader can also be used to loop over JSON values appended to the file:

    t, err := newTailReader("somefile")
    if err != nil {
        log.Fatal(err)
    }
    defer t.Close()
    dec := json.NewDecoder(t)
    for {
        var v SomeType
        if err := dec.Decode(&v); err != nil {
           log.Fatal(err)
        }
        fmt.Println("the value is ", v)
    }
    

    There are a couple of advantages this approach has over the goroutine approach outlined in the question. The first is that shutdown is easy. Just close the file. There's no need to signal the goroutine that it should exit. The second advantage is that many packages work with io.Reader.

    The sleep time can be adjusted up or down to meet specific needs. Decrease the time for lower latency and increase the time to reduce CPU use. A sleep of 100ms is probably fast enough for data that's displayed to humans.

    0 讨论(0)
  • 2021-01-11 20:19

    Check out this Go package for reading from continuously updated files (tail -f): https://github.com/hpcloud/tail

    t, err := tail.TailFile("filename", tail.Config{Follow: true})
    for line := range t.Lines {
        fmt.Println(line.Text)
    }
    
    0 讨论(0)
提交回复
热议问题