2013-07-25 13 views
8

jak mogę odczytać ostatnie dwie linie z dużego pliku dziennika bez załadowania go do pamięci?Jak odczytywać ostatnie wiersze dużego pliku z Go co 10 sekund

muszę ją przeczytać co 10 sekund (na komputerze Win) ... a ja utknąłem próbuje odczytać ostatnie linie ..

package main 

import (
    "fmt" 
    "time" 
    "os" 
) 

const MYFILE = "logfile.log" 

func main() { 
    c := time.Tick(10 * time.Second) 
    for now := range c { 
     readFile(MYFILE) 
    } 
} 

func readFile(fname string){ 
    file, err:=os.Open(fname) 
    if err!=nil{ 
     panic(err) 
    } 
    buf:=make([]byte, 32) 
    c, err:=file.ReadAt(32, ????) 
    fmt.Printf("%s\n", c) 


} 

Plik dziennika jest coś takiego:

07/25/2013 11:55:42.400, 0.559 
07/25/2013 11:55:52.200, 0.477 
07/25/2013 11:56:02.000, 0.463 
07/25/2013 11:56:11.800, 0.454 
07/25/2013 11:56:21.600, 0.424 
07/25/2013 11:56:31.400, 0.382 
07/25/2013 11:56:41.200, 0.353 
07/25/2013 11:56:51.000, 0.384 
07/25/2013 11:57:00.800, 0.393 
07/25/2013 11:57:10.600, 0.456 

Dzięki!

Odpowiedz

9

Możesz użyć file.Seek() lub file.ReadAt() prawie do końca, a następnie do czytania do przodu. Możesz tylko oszacować, od czego zacząć poszukiwania, chyba że wiesz, że 2 linie = x bajty.

można uzyskać długość pliku za pomocą os.Stat(name)

Oto przykład na podstawie ReadAt, Stat, a próbka pliku dziennika:

package main 

import (
    "fmt" 
    "os" 
    "time" 
) 

const MYFILE = "logfile.log" 

func main() { 
    c := time.Tick(10 * time.Second) 
    for _ = range c { 
     readFile(MYFILE) 
    } 
} 

func readFile(fname string) { 
    file, err := os.Open(fname) 
    if err != nil { 
     panic(err) 
    } 
    defer file.Close() 

    buf := make([]byte, 62) 
    stat, err := os.Stat(fname) 
    start := stat.Size() - 62 
    _, err = file.ReadAt(buf, start) 
    if err == nil { 
     fmt.Printf("%s\n", buf) 
    } 

} 
+0

Dzięki @Joshua było to lepsze podejście do mnie – Goku

+0

bym file.Seek (62, 2) z koniec zamiast, a potem tylko plik.Re reklama z bieżącej pozycji. file.Seek, podejrzewam, jest znacznie tańszy niż os.Stat. – alex

+0

@Joshua - A co powiesz na czytanie linii, której nie znamy rozmiaru bajtu? – Mir

3

myślę kombinacja File.Seek(0, 2) i File.Read() powinien praca.

Wywołanie Seek powoduje przejście do końca pliku. Możesz Seek na pozycję trochę przed EOF, aby uzyskać kilka ostatnich linii. Następnie musisz Read do EOF i po prostu spać w swojej goroutine przez 10 sekund; następny Read ma szansę uzyskać więcej danych.

Możesz wyrwać pomysł (i logikę skanowania wstecznego dla początkowo pokazującego kilka ostatnich linii) z GNU tail's source.

+0

Nice! Źródła planu9 są nieco krótsze: http://swtch.com/usr/local/plan9/src/cmd/tail.c – nes1983

1

Cóż, to tylko surowe pomysł, a może nie jest najlepszym sposobem, należy sprawdzić i poprawić go, ale wydaje się działać ...

Mam nadzieję, że doświadczeni użytkownicy Go mogłoby przyczynić się zbyt ..

z Stat można uzyskać rozmiaru pliku i od niego uzyskać przesunięcie do użytku z ReadAt

func readLastLine(fname string) { 
    file, err := os.Open(fname) 
    if err != nil { 
     panic(err) 
    } 
    defer file.Close() 

    fi, err := file.Stat() 
    if err != nil { 
     fmt.Println(err) 
    } 

    buf := make([]byte, 32) 
    n, err := file.ReadAt(buf, fi.Size()-int64(len(buf))) 
    if err != nil { 
     fmt.Println(err) 
    } 
    buf = buf[:n] 
    fmt.Printf("%s", buf) 

} 
Powiązane problemy