Go 如何每隔10秒读取一个大文件的最后几行
如何从一个大日志文件中读取最后两行,而不将其完全加载到内存中 我需要每10秒读一次(在Win机器上)…我一直在努力读最后一行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)
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
}