【问题标题】:portable way to monitor a file for changes监视文件更改的便携式方法
【发布时间】:2015-06-29 06:49:38
【问题描述】:

我实际上正在实现一个非常简单的tail(1) 版本。在 FreeBSD 中,我使用 kqueue 来监视文件的更改,然后将附加的行打印到输出中。但这不是一种可移植的方式,因为kqueue 仅在 BSD 系列中可用。是否有一种通用、高效且独立于平台的方法来监视 UNIX 中的文件更改?我不喜欢使用外部库。

这是我写的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>

void die(const char*);

#define MAXLINE     1024

int main(int argc, char *argv[])
{
    int fdes;
    int kq;
    int nev;
    int flags;
    off_t curoff;

    char line[MAXLINE + 1];
    ssize_t nbytes;

    struct kevent change, event;

    if (2 != argc)
    {
        fprintf(stderr, "Usage: %s path\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if (-1 == (fdes = open(argv[1], O_RDONLY)))
        die("open()");

    if (-1 == (curoff = lseek(fdes, 0, SEEK_END)))
        die("lseek()");

    int ch = 0;
    int i = 0;
    while (i < 10)
    {
        read(fdes, &ch, 1);

        if (ch == '\n')
            i++;

        if (10 > i)
            lseek(fdes, --curoff, SEEK_SET);
    }

    if (-1 == (flags = fcntl(fdes, F_GETFL)))
        die("fcntl()");

    flags |= O_NONBLOCK;

    if (-1 == fcntl(fdes, F_SETFL, flags))
        die("fcntl()1");

    while ((nbytes = read(fdes, line, MAXLINE)) > 0)
        if (write(STDOUT_FILENO, line, nbytes) != nbytes)
            die("write()");

    if (-1 == (kq = kqueue()))
        die("kqueue()");

    EV_SET(&change, fdes, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
     NOTE_EXTEND | NOTE_WRITE | NOTE_DELETE, 0, NULL);

    if (-1 == kevent(kq, &change, 1, NULL, 0, NULL))
        die("kevent()");

    for (;;)
    {
        if (-1 == (nev = kevent(kq, NULL, 0, &event, 1, NULL)))
            die("kevent()");

        if (nev > 0)
        {
            if (event.fflags & NOTE_WRITE || event.fflags & NOTE_EXTEND)    
            {
                while ((nbytes = read(fdes, line, MAXLINE)) > 0)
                    if (write(STDOUT_FILENO, line, nbytes) != nbytes)
                        die("write()");
            }
            else if (NOTE_DELETE & event.fflags)
            {
                printf("The file has been deleted\n");
                break;
            }
        }
    }

    return 0;
}

void die(const char *str)
{
    perror(str);
    exit(EXIT_FAILURE);
}

【问题讨论】:

  • 最便携的方法是轮询所有文件并查找文件修改时间戳中的更改(使用例如stat)。不过,我不会称其为高效,它当然不适用于没有修改时间戳的文件系统上的文件(尽管这些天应该很少而且相距甚远)。

标签: c unix tail


【解决方案1】:

您可以继续循环执行 read()。如果您读取零字节, 检查错误。如果没有错误,那么您已经达到 EOF。在 EOF, stat() 文件名,如果它消失了,则文件被删除。如果 stat 返回,比较 stat 的 st_dev 和 st_ino 字段 fstat 的结果(打开文件时缓存它)。如果他们是 不同的是,路径被删除并重新创建。只要你睡 在尝试另一次读取之前注意删除检查。

【讨论】:

  • 正如我所说,“只要你在删除检查后就睡觉......”
猜你喜欢
  • 2021-07-27
  • 1970-01-01
  • 2014-05-18
  • 1970-01-01
  • 1970-01-01
  • 2011-01-26
  • 1970-01-01
  • 2015-04-16
  • 2012-09-28
相关资源
最近更新 更多