=Start=
缘由:
想着在学习Go 语言的过程中,尝试把常见命令的功能用Go 语言实现一遍,既加强了Go 语言的学习,又充实了自己的代码仓库,一举两得,何乐而不为?
正文:
参考解答:
大体上来说,要用Go 语言(或是其它的什么编程语言)来实现 tail -f
命令的功能,大致方法和逻辑不外乎:
- 直接调用 tail -f 命令,读取命令的输出;
- 理解 tail -f 命令的原理,照着原理手工实现;
- 调用已有的成熟的第三方库;
第一种调用外部命令的方式就不在这说了,可以参考之前记录的通过os.exec调用系统命令的文章。
第二种是根据 tail -f 命令的原理完全手工实现,个人觉得必要性不大,主要有几点原因:1、原理本身并不复杂,主要是通过定期轮询或是系统底层API的通知机制获知文件内容发生变动,然后从上一次(或第一次)记录的文件偏移offset开始,使用fseek移动到变动内容处调用read/fread进行读取后打印出来;2、虽然原理不复杂,但是要想实现的非常完备也是很困难的,需要考虑各种各样的异常/复杂情况,自己实现性价比不高;3、自己实现的一般不会比成熟的第三方库效率高或是性能好,没有实际使用价值或是实际使用价值很低。
第三种就是调用已有的成熟的第三方库,这里主要是指 github.com/hpcloud/tail 这个。
上面说了一堆,主要是为了引出这个库的使用方法介绍:
package main import ( "fmt" "github.com/hpcloud/tail" "time" ) func main() { filename := "/private/tmp/test" tails, err := tail.TailFile(filename, tail.Config{ ReOpen: true, Follow: true, // Location: &tail.SeekInfo{Offset: 0, Whence: 2}, MustExist: false, Poll: true, }) if err != nil { fmt.Println("tail file err:", err) return } var msg *tail.Line var ok bool for { msg, ok = <-tails.Lines if !ok { fmt.Printf("tail file close reopen, filename:%s\n", tails.Filename) time.Sleep(100 * time.Millisecond) continue } fmt.Printf("msg(%T): %v\n", msg, msg) fmt.Printf("msg(%T): %v\n", msg.Text, msg.Text) } }
以上。
参考链接:
- golang基础-tailf日志组件使用
- Reading log files as they’re updated in Go
- How would I read a growing file in Go?
- https://github.com/hpcloud/tail
https://godoc.org/github.com/hpcloud/tail#Line - golang模仿tail命令,显示文件末尾指定行数的文件内容
- https://golang.org/pkg/os/#FileInfo
- https://golang.org/pkg/os/#File.Seek
=END=