"tail -f"式发电机



我在Python中有一个方便的函数:

def follow(path):
    with open(self.path) as lines:
        lines.seek(0, 2)  # seek to EOF
        while True:
            line = lines.readline()
            if not line:
                time.sleep(0.1)
                    continue
                yield line 

它的作用类似于UNIXtail -f:您可以在文件的最后一行出现时获得它们。这很方便,因为您可以在不阻塞的情况下获得生成器,并将其传递给另一个函数。

然后我不得不在围棋中做同样的事情。我是这门语言的新手,所以我不确定我所做的是否足够地道/正确。

这是代码:

func Follow(fileName string) chan string {
    out_chan := make(chan string)
    file, err := os.Open(fileName)
    if err != nil {
        log.Fatal(err)
    }
    file.Seek(0, os.SEEK_END)
    bf := bufio.NewReader(file)
    go func() {
        for {
            line, _, _ := bf.ReadLine()
            if len(line) == 0 {
                time.Sleep(10 * time.Millisecond)
            } else {
                out_chan <- string(line)
            }
        }
        defer file.Close()
        close(out_chan)
    }()
    return out_chan
}

在Go中有更干净的方法吗?我有一种感觉,对这样的事情使用异步调用是过分的,这真的让我很困扰

在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
}

这个读卡器可以在任何可以使用io的地方使用。读卡器。以下是如何使用bufio在线路上循环。扫描仪:

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)
}

读取器还可以用于循环附加到文件的JSON值:

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)
}

与问题中概述的goroutine方法相比,这种方法有几个优点。首先,关闭很容易。只需关闭文件。没有必要向goroutine发出应该退出的信号。第二个优点是许多包都可以使用io.Reader.

睡眠时间可以上下调整,以满足特定需求。减少时间以降低延迟,增加时间以减少CPU使用。100毫秒的睡眠可能足够快,可以向人类显示数据。

查看这个Go包,以便从不断更新的文件中读取(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)
}

相关内容

  • 没有找到相关文章

最新更新