2015-02-11 86 views
2

我需要監視特定文件類型(帶有已知擴展名)在Linux中的特定文件夾中的創建。我知道inotify只會看現有的文件。我理解正確嗎?linux C++通知文件類型創建

是否有替代inotify(或類似的軟件包),這將允許我通過文件類型監視文件創建?

編輯: 我需要的是通過掩碼監視文件創建。我需要監視* .json的路徑,而忽略其他文件類型。

+0

'inotify'很棒,當然它上面有一些庫可以使它更容易使用。 – 2015-02-11 13:23:25

+2

Inotify確實只會監視現有文件,因爲監視不存在的東西是不可能的。但是,您忘記了您也可以監視*目錄*。 – 2015-02-11 13:26:16

+4

關於「文件類型」,在Linux中(或者通常在POSIX/UNIX世界中)並沒有真正不同的「文件類型」。但是,如果您監視目錄中的新文件,則可以檢查文件擴展名以查看它是否是您想要的。 – 2015-02-11 13:27:50

回答

3

這聽起來像是一個很好的使用案例inotifyman page有一個很好的例子,很容易轉移到你的問題。

下面是可用於像

$ myprog /tmp '*.o' '*.a' 

看目錄/tmp爲創造*.o*.a文件一個小程序。請注意,模式被引用以防止shell的擴展。該程序將永久運行,直到被中斷SIGINT(按Ctrl + C)。

我使用fnmatch將創建的文件的名稱與模式匹配,並安裝用於設置全局標誌的SIGINT的信號處理程序。

#include <assert.h> 
#include <errno.h> 
#include <fnmatch.h> 
#include <limits.h> 
#include <signal.h> 
#include <stddef.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/inotify.h> 
#include <unistd.h> 

我定義了一個小預處理宏對齊使用GCC的__attribute__擴展緩衝區。稍後當我們實際使用這個宏的時候更多。

#ifdef __GNUC__ 
# define ALIGNAS(TYPE) __attribute__ ((aligned(__alignof__(TYPE)))) 
#else 
# define ALIGNAS(TYPE) /* empty */ 
#endif 

這是一個全局標誌,我們將在信號處理程序中設置以表示程序應該正常退出。

static volatile int interrupted = 0; 

而這是信號處理程序本身。

static void 
interruption_handler(const int s) 
{ 
    if (s == SIGINT) 
    interrupted = 1; 
} 

這個函數是程序的工作馬。

static int 
monitor_directory(const char *const directory, 
        const char *const *const patterns, 
        const size_t pattern_count) 
{ 
    int notifyfd = -1; 
    int watchfd = -1; 
    int ret = 0; 
    const char * errmsg = "unknown error"; 

首先,我們初始化的inotifyinotify_init將返回一個文件描述符,我們可以從read()通知。我使用阻塞I/O,因此read()將阻塞,直到發生事件。

notifyfd = inotify_init(); 
    if (notifyfd < 0) 
    { 
     errmsg = "inotify_init"; 
     goto catch; 
    } 

現在我們註冊要觀看的文件。在我們的例子中,我們想要觀看一個目錄(directory)來創建新文件(IN_CREATE)。返回的文件描述符可用於告知(如果發生事件)它屬於哪個觀察文件。但是,既然我們只看一個文件(這恰好是一個目錄),我們並不需要這些信息。

watchfd = inotify_add_watch(notifyfd, directory, IN_CREATE); 
    if (watchfd < 0) 
    { 
     errmsg = "inotify_add_watch"; 
     goto catch; 
    } 

現在一切都設置正確,我們可以開始read()從通知文件描述符荷蘭國際集團。

while (1) 
    { 

它事先不知道有多少來自的inotify描述符read通話將讀取所以我們要讀入緩衝區char。我們希望妥善調整,堅韌。請參閱手冊頁以獲取更多關於此的評論。

 char buffer[sizeof(struct inotify_event) + NAME_MAX + 1] ALIGNAS(struct inotify_event); 
     const struct inotify_event * event_ptr; 

read()來自文件描述符。如果我們被打斷,read()將會解鎖並返回-1,因爲如果發生錯誤將會返回-1。

 ssize_t count = read(notifyfd, buffer, sizeof(buffer)); 
     if (count < 0) 
     { 
      if (interrupted) 
      goto finally; 
      errmsg = "read"; 
      goto catch; 
     } 

我們有一個新事件,處理它。

 event_ptr = (const struct inotify_event *) buffer; 
     assert(event_ptr->wd == watchfd); 
     assert(event_ptr->mask & IN_CREATE); 
     if (event_ptr->len) 
     { 
      size_t i; 

嘗試使用我們的每種模式匹配文件名。我們不得不做一些清理工作。 close()inotify創建的文件描述符將導致它釋放任何關聯的資源。

finally: 
    if (watchfd >= 0) 
    { 
     int status = close(watchfd); 
     watchfd = -1; 
     if (status < 0) 
     { 
      errmsg = "close(watchfd)"; 
      goto catch; 
     } 
    } 
    if (notifyfd >= 0) 
    { 
     int status = close(notifyfd); 
     notifyfd = -1; 
     if (status < 0) 
     { 
      errmsg = "close(notifyfd)"; 
      goto catch; 
     } 
    } 
    return ret; 
catch: 
    if (errmsg && errno) 
    perror(errmsg); 
    ret = -1; 
    goto finally; 
} 

這就是我們如何將所有東西都鉤在一起並運行程序。

int 
main(const int argc, const char *const *const argv) 
{ 
    if (argc < 3) 
    { 
     fprintf(stderr, "usage: %s DIRECTORY PATTERN...\n", argv[0]); 
     return EXIT_FAILURE; 
    } 
    { 
    struct sigaction sa; 
    sa.sa_handler = interruption_handler; 
    sigemptyset(&sa.sa_mask); 
    sa.sa_flags = 0; 
    sigaction(SIGINT, &sa, NULL); 
    } 
    if (monitor_directory(argv[1], argv + 2, argc - 2) < 0) 
    return EXIT_FAILURE; 
    return EXIT_SUCCESS; 
} 
+0

這是一個方便的樣本代碼,除了'C++'標籤 - 這個'catch'是一個關鍵字。 – Petesh 2015-02-11 15:05:15

+0

哇。非常感謝你。我會檢查這個。 – mousomer 2015-02-11 15:22:28

+1

@Petesh我決定寫一個C示例程序,使其更加通用。 (這個問題被標記爲'c'和'C++'。)我習慣於在C中使用'catch'作爲標籤,以清楚地表明我正在使用'goto'來模擬異常處理。是的,這意味着代碼不會編譯爲C++代碼,但我認爲這更多的是功能而不是bug,因爲它提醒我們不要在C++中使用'goto'錯誤處理。但是,如果您需要雙語言支持,重命名標籤將是一個小修改。 – 5gon12eder 2015-02-11 15:22:39