我需要監視特定文件類型(帶有已知擴展名)在Linux中的特定文件夾中的創建。我知道inotify只會看現有的文件。我理解正確嗎?linux C++通知文件類型創建
是否有替代inotify(或類似的軟件包),這將允許我通過文件類型監視文件創建?
編輯: 我需要的是通過掩碼監視文件創建。我需要監視* .json的路徑,而忽略其他文件類型。
我需要監視特定文件類型(帶有已知擴展名)在Linux中的特定文件夾中的創建。我知道inotify只會看現有的文件。我理解正確嗎?linux C++通知文件類型創建
是否有替代inotify(或類似的軟件包),這將允許我通過文件類型監視文件創建?
編輯: 我需要的是通過掩碼監視文件創建。我需要監視* .json的路徑,而忽略其他文件類型。
這聽起來像是一個很好的使用案例inotify。 man 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";
首先,我們初始化的inotify。 inotify_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;
}
這是一個方便的樣本代碼,除了'C++'標籤 - 這個'catch'是一個關鍵字。 – Petesh 2015-02-11 15:05:15
哇。非常感謝你。我會檢查這個。 – mousomer 2015-02-11 15:22:28
@Petesh我決定寫一個C示例程序,使其更加通用。 (這個問題被標記爲'c'和'C++'。)我習慣於在C中使用'catch'作爲標籤,以清楚地表明我正在使用'goto'來模擬異常處理。是的,這意味着代碼不會編譯爲C++代碼,但我認爲這更多的是功能而不是bug,因爲它提醒我們不要在C++中使用'goto'錯誤處理。但是,如果您需要雙語言支持,重命名標籤將是一個小修改。 – 5gon12eder 2015-02-11 15:22:39
'inotify'很棒,當然它上面有一些庫可以使它更容易使用。 – 2015-02-11 13:23:25
Inotify確實只會監視現有文件,因爲監視不存在的東西是不可能的。但是,您忘記了您也可以監視*目錄*。 – 2015-02-11 13:26:16
關於「文件類型」,在Linux中(或者通常在POSIX/UNIX世界中)並沒有真正不同的「文件類型」。但是,如果您監視目錄中的新文件,則可以檢查文件擴展名以查看它是否是您想要的。 – 2015-02-11 13:27:50