Ответ 1
Я предлагаю создать обертку вокруг читателя, который спит на 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.Reader. Вот как перебирать строки, используя 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)
}
Считыватель также можно использовать для циклического перемещения значений 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.