Go语言学习#15-如何实现tail -f命令的功能


=Start=

缘由:

想着在学习Go 语言的过程中,尝试把常见命令的功能用Go 语言实现一遍,既加强了Go 语言的学习,又充实了自己的代码仓库,一举两得,何乐而不为?

正文:

参考解答:

大体上来说,要用Go 语言(或是其它的什么编程语言)来实现 tail -f 命令的功能,大致方法和逻辑不外乎:

  1. 直接调用 tail -f 命令,读取命令的输出;
  2. 理解 tail -f 命令的原理,照着原理手工实现;
  3. 调用已有的成熟的第三方库;

第一种调用外部命令的方式就不在这说了,可以参考之前记录的通过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)
    }
}

以上。

 

参考链接:

=END=


发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注