Go 如何每隔10秒读取一个大文件的最后几行

Go 如何每隔10秒读取一个大文件的最后几行,go,Go,如何从一个大日志文件中读取最后两行,而不将其完全加载到内存中 我需要每10秒读一次(在Win机器上)…我一直在努力读最后一行 package main import ( "fmt" "time" "os" ) const MYFILE = "logfile.log" func main() { c := time.Tick(10 * time.Second) for now := range c { readFile(MYFILE)

如何从一个大日志文件中读取最后两行,而不将其完全加载到内存中

我需要每10秒读一次(在Win机器上)…我一直在努力读最后一行

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)


}
日志文件类似于:

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
谢谢

您可以使用或,直到接近结尾,然后向前阅读。除非知道2行=x字节,否则只能估计从何处开始搜索

您可以使用

下面是一个基于ReadAt、Stat和示例日志文件的示例:

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

}

我认为
File.Seek(0,2)
File.Read()
的组合应该可以工作

Seek
调用将您带到文件的末尾。您可以
搜索
到EOF前面一点的位置,以获取最后几行。然后你
阅读
直到EOF,然后在goroutine中睡眠10秒;下一步
Read
有机会获取更多数据


您可以从中获取想法(以及最初显示最后几行的扫描逻辑)。

好吧,这只是一个原始想法,可能不是最好的方法,您应该检查并改进它,但似乎有效

我希望有经验的围棋用户也能做出贡献

使用,您可以获得文件的大小,并从中获得用于的偏移量


有些人会来到这个页面,寻找高效地读取日志文件的最后一行(比如tail命令行工具)

这是我阅读大文件最后一行的版本。它使用了前面的两个建议(使用和文件)

它逐字节向后读取文件(无需设置缓冲区大小),直到找到行的开头或文件的开头

func getLastLineWithSeek(filepath string) string {
    fileHandle, err := os.Open(filepath)

    if err != nil {
        panic("Cannot open file")
        os.Exit(1)
    }
    defer fileHandle.Close()

    line := ""
    var cursor int64 = 0
    stat, _ := fileHandle.Stat()
    filesize := stat.Size()
    for { 
        cursor -= 1
        fileHandle.Seek(cursor, io.SeekEnd)

        char := make([]byte, 1)
        fileHandle.Read(char)

        if cursor != -1 && (char[0] == 10 || char[0] == 13) { // stop if we find a line
            break
        }

        line = fmt.Sprintf("%s%s", string(char), line) // there is more efficient way

        if cursor == -filesize { // stop if we are at the begining
            break
        }
    }

    return line
}

谢谢@Joshua,这是处理meI的更好方法。从结尾处搜索(62,2),然后直接归档。从当前位置读取。我怀疑file.Seek比os.Stat.@Joshua便宜得多-读一行我们不知道字节大小的行怎么样?很好!plan9震源略短:
func getLastLineWithSeek(filepath string) string {
    fileHandle, err := os.Open(filepath)

    if err != nil {
        panic("Cannot open file")
        os.Exit(1)
    }
    defer fileHandle.Close()

    line := ""
    var cursor int64 = 0
    stat, _ := fileHandle.Stat()
    filesize := stat.Size()
    for { 
        cursor -= 1
        fileHandle.Seek(cursor, io.SeekEnd)

        char := make([]byte, 1)
        fileHandle.Read(char)

        if cursor != -1 && (char[0] == 10 || char[0] == 13) { // stop if we find a line
            break
        }

        line = fmt.Sprintf("%s%s", string(char), line) // there is more efficient way

        if cursor == -filesize { // stop if we are at the begining
            break
        }
    }

    return line
}