C语言中“tail -f”功能的自定义实现

2 投票
3 回答
1846 浏览
提问于 2025-04-15 11:42

编辑:最后我用了 inotify。正如 stefanB 所说,inotify 是最合适的选择。我找到一个使用 inotify 来实现 -f 模式的 tail 克隆,链接在这里:inotail

原始问题内容:

我正在尝试在一个 C 项目中实现 "tail -f" 的逻辑。为了原型开发,我用 Python 写了如下代码:


    # A forever loop, each 5 seconds writes a line into file.txt
    from time import *

    while 1:
        sleep(5)
        file = open("file.txt", "a")
        file.write("This is a test\n")
        file.close()

下面的代码会跟踪 file.txt 的末尾(这个文件是由上面的代码更新的)


    # tail -f 
    from time import *

    file = open("file.txt", "r")
    file.seek(0, 2)

    while 1:
      line = file.readline()
      if not line:
          sleep(1)
      else:
          print line

    file.close()

一切都运行得很好,但 C 的实现却不行(没有检查错误的代码)。这里省略了 stdio.h、string.h 和 unistd.h 的包含(颜色化隐藏了头文件的包含代码)。


    #define LINE_LEN 256

    int main(int argc, char **argv)
    {
        FILE *f;
        char line[LINE_LEN];

        f = fopen("file.txt", "r");

        fseek(f, 0, SEEK_END);

        while (1)
        {
            fgets(line, LINE_LEN, f);

            if (strlen(line) == 0)
            {
                sleep(1);
            }
            else
            {
                printf("Readed: %s", line);
            } 
        }

        fclose(f);

        return 0;
    }

有什么想法吗?

用 poll() 来实现这个功能是不是个好主意,而不是使用目前的解决方案?

提前谢谢你。

3 个回答

2

来自tail手册页面

-f 当文件到达末尾时,不要停止,而是等待有新的数据被添加到输入中。如果文件被替换(也就是,inode编号发生变化),tail会重新打开文件并继续读取。如果文件被截断,tail会将其读取位置重置到开头。这使得tail在监视可能会被轮换的日志文件时更加有用。如果标准输入是管道,-f选项会被忽略,但如果是FIFO则不会。

所以,你可以这样做:

  1. 使用stat()来读取文件的inode编号
  2. 显示该文件的内容。保存文件描述符的位置,比如,p = ftell(fd)
  3. 再次使用stat(),查看inode是否发生了变化。如果有变化,从位置p开始显示文件的内容
  4. 重复以上步骤
3

一旦一个文件指针(FILE *)遇到错误或者到达文件末尾,它的内部状态就会被设置成这样:在后续的调用中,它会继续返回错误或者文件结束的状态。为了让它重新尝试从文件中读取更多数据,你需要在休眠结束后调用 clearerr(f); 来清除这个文件结束的状态。

3

编辑
看起来 inotify 是个不错的选择。它从 Linux 内核 2.6.13 版本开始就已经包含在内了。这是 IBM DeveloperWorks 上关于 inotify 的一篇文章

之前的回答:

可以看看 Linux 的 文件变更监控器(在 Linux 内核 2.4.x 及以上版本中)。这是一个框架,允许你订阅文件的变化,当文件发生变化时,内核会给你发送通知。这种方式比轮询要好。

想了解如何轮询文件变化,可以查看 等待文件变化轮询文件变化 这两个部分的 示例

我还没有尝试过这个。

撰写回答