2015-06-29 5 views
1

Я на самом деле реализую очень простую версию хвоста (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); 
} 
+3

Самый портативный способ - опросить все файлы и искать изменения в временной шкале изменения файлов (используя, например, ['stat'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatat.html)). Я бы не назвал это эффективным, хотя и, конечно, не будет работать для файлов в файловых системах, у которых нет метки времени модификации (хотя в наши дни это должно быть немного и далеко друг от друга). –

ответ

0

Вы можете просто продолжать делать чтение() в цикле. Если вы читаете нулевые байты, проверьте наличие ошибки. Если нет ошибки, вы попали в EOF. В EOF, stat() имя файла, если оно ушло, файл был удален. Если stat возвращает, сравните st_dev и st_ino поля stat с результаты из fstat (кешируйте это при открытии файла). Если они равны , путь был удален и повторно создан. Сон до тех пор, пока вы заботитесь после проверки удаления, прежде чем пытаться читать.

+1

О, мальчик, ты не против, чтобы привязать ядро ​​или два. –

+0

Как я уже сказал, «Спийте, пока вы заботитесь после проверки на удаление ...» – user464502