【實(shí)戰(zhàn)技巧】使用inotify實(shí)現(xiàn)實(shí)時(shí)文件監(jiān)控

【實(shí)戰(zhàn)技巧】使用inotify實(shí)現(xiàn)實(shí)時(shí)文件監(jiān)控

開篇

? 之前閱讀《Linux系統(tǒng)編程》時(shí),留意到了一個(gè)Linux原生接口inotify杭措。它能夠監(jiān)控文件的移動(dòng)、讀取、寫入和刪除等操作午阵。今天利用空閑時(shí)間,簡(jiǎn)單研究了一下如何使用這個(gè)接口,并在這里記錄下來底桂,方便將來需要查詢和參考植袍。

概述

? inotify 是 Linux 內(nèi)核提供的一種文件系統(tǒng)事件監(jiān)控機(jī)制,允許用戶空間程序監(jiān)視文件或目錄的各種操作籽懦。
? 通過注冊(cè)監(jiān)聽事件于个,程序可以實(shí)時(shí)捕獲文件的創(chuàng)建、刪除暮顺、移動(dòng)和修改等操作厅篓,無需輪詢,極大地提高了效率和實(shí)時(shí)性捶码。inotify 提供了一種高效的方式來構(gòu)建實(shí)時(shí)文件同步羽氮、監(jiān)控日志變更和自動(dòng)化任務(wù)等應(yīng)用,是現(xiàn)代 Linux 系統(tǒng)編程中不可或缺的一部分惫恼。

基礎(chǔ)接口

  • int inotify_init(void) / int inotify_init1(int flags)
原型 int inotify_init(void)
功能 初始化一個(gè)新的 inotify 實(shí)例档押,并返回一個(gè)新的文件描述符,用于后續(xù)的操作祈纯。
參數(shù) flags:
? IN_CLOEXEC: 在執(zhí)行 execve() 后關(guān)閉文件描述符(FD_CLOEXEC)令宿。
? IN_NONBLOCK:在新的文件描述符上設(shè)置 O_NONBLOCK 文件狀態(tài)標(biāo)志。使用這個(gè)標(biāo)志可以避免額外調(diào)用 fcntl(2) 來達(dá)到同樣的效果腕窥。
返回值 成功:返回一個(gè)新的文件描述符粒没,用于標(biāo)識(shí) inotify 實(shí)例。
失斢桶骸:返回 -1革娄,并設(shè)置 errno 來指示錯(cuò)誤類型。
  • int inotify_add_watch(int fd, const char *pathname, uint32_t mask)
原型 int inotify_add_watch(int fd, const char *pathname, uint32_t mask)
功能 向指定的 inotify 實(shí)例中添加一個(gè)新的文件或目錄的監(jiān)視冕碟,并指定要監(jiān)視的事件類型拦惋。
參數(shù) fd
? inotify_init 返回的文件描述符,標(biāo)識(shí)要添加監(jiān)視的 inotify 實(shí)例安寺。
pathname:要監(jiān)視的文件或目錄的路徑名厕妖。
mask:要監(jiān)視的事件類型的位掩碼,可以是以下之一或多個(gè)值的按位或組合:
? IN_ACCESS:文件被訪問挑庶。
? IN_MODIFY:文件被修改言秸。
? IN_ATTRIB:文件屬性被修改。
? IN_CLOSE_WRITE:可寫文件被關(guān)閉迎捺。
? IN_CLOSE_NOWRITE:不可寫文件被關(guān)閉等举畸。
返回值 成功:返回一個(gè)新的監(jiān)視描述符,用于標(biāo)識(shí)此次監(jiān)視凳枝。
失敵凇:返回 -1跋核,并設(shè)置 errno 來指示錯(cuò)誤類型。
  • int inotify_rm_watch(int fd, int wd)
原型 int inotify_rm_watch(int fd, int wd)
功能 從 inotify 實(shí)例中移除先前添加的監(jiān)視叛买。
參數(shù) fd:inotify_init 返回的文件描述符砂代,標(biāo)識(shí)要移除監(jiān)視的 inotify 實(shí)例。
wd:要移除的監(jiān)視描述符率挣,即調(diào)用 inotify_add_watch 返回的監(jiān)視描述符刻伊。
返回值 成功:返回 0。
失斀饭Α:返回 -1捶箱,并設(shè)置 errno 來指示錯(cuò)誤類型。

源碼示例

  • 需求: 實(shí)現(xiàn)監(jiān)聽指定路徑下文件的修改事件蛾茉,在事件發(fā)生時(shí)實(shí)時(shí)打印讼呢。
  • 實(shí)現(xiàn): inotify接口使用起來比較簡(jiǎn)單撩鹿,大致分為三個(gè)步驟:
    inotify初始化
    ② 增加監(jiān)視對(duì)象以及監(jiān)聽類型
    ③ 等待事件觸發(fā)谦炬,可以結(jié)合I/O復(fù)用。

整理流程比較簡(jiǎn)單节沦,這里簡(jiǎn)單列舉一下事件觸發(fā)響應(yīng)和測(cè)試流程示例:

  • 事件觸發(fā)響應(yīng)流程
    簡(jiǎn)單展示 inotify 阻塞模式的使用示例键思,阻塞等待事件觸發(fā),并及時(shí)處理甫贯。
int InotifyManager::WaitForEvents() {
    const int bufferSize = 1024; // 根據(jù)實(shí)際需求調(diào)整緩沖區(qū)大小
    char buffer[bufferSize];

    ssize_t numRead = read(inotifyFd, buffer, bufferSize);
    if (numRead == -1) {
        if (errno != EAGAIN) {
            std::cerr << "Error reading from inotify: " << strerror(errno) << std::endl;
            return -1;
        }
        return 0;
    }

    // 處理所有事件
    int offset = 0;
    while (offset < numRead) {
        struct inotify_event* event = reinterpret_cast<struct inotify_event*>(&buffer[offset]);
        if (event->len > 0) {
            std::cout << "Inotify event: " << event->name;
            if (event->mask & IN_CREATE)
                std::cout << " created";
            if (event->mask & IN_DELETE)
                std::cout << " deleted";
            std::cout << std::endl;
        }
        offset += sizeof(struct inotify_event) + event->len;
    }

    return 0;
}
  • 測(cè)試代碼
    循環(huán)等待inotify事件吼鳞,由于是阻塞模式,不會(huì)導(dǎo)致空轉(zhuǎn)叫搁。
int main() {
    InotifyManager inotifyManager;

    // 監(jiān)聽當(dāng)前目錄下的文件創(chuàng)建和刪除事件
    inotifyManager.AddWatch(".", IN_CREATE | IN_DELETE);

    while (true) {
        // 等待并處理事件
        inotifyManager.WaitForEvents();
    }

    return 0;
}

效果驗(yàn)證

  • 驗(yàn)證流程:
    ① 左邊窗口執(zhí)行監(jiān)聽程序赔桌。
    ② 右邊窗口先后執(zhí)行創(chuàng)建和刪除hello文件。
  • 驗(yàn)證效果:
    ? 監(jiān)聽程序能夠及時(shí)打印出對(duì)應(yīng)創(chuàng)建和刪除事件渴逻。
    驗(yàn)證.png

總結(jié)

  • 從使用流程來看疾党,inotify用起來比較簡(jiǎn)單,只需要初始化惨奕、添加事件和讀取事件即可雪位。
  • inotify 句柄也可以通過 I/O 多路復(fù)用(如 epoll/select/poll)進(jìn)行監(jiān)聽,實(shí)現(xiàn)事件的及時(shí)響應(yīng)梨撞。
  • inotify 使用場(chǎng)景也比較多雹洗,例如界面實(shí)時(shí)刷新顯示文件;監(jiān)聽配置文件變更動(dòng)態(tài)加載配置卧波;作為調(diào)試手段时肿,模擬外部事件觸發(fā)內(nèi)部響應(yīng)以及記錄一些敏感文件的修改記錄等等。
  • 了解這種原生接口港粱,以后如果有需求螃成,能夠讓實(shí)現(xiàn)多一種方式,同時(shí)減少開發(fā)中的復(fù)雜性和時(shí)間成本,或許也能夠少走一些“彎路”锈颗。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末顷霹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子击吱,更是在濱河造成了極大的恐慌淋淀,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件覆醇,死亡現(xiàn)場(chǎng)離奇詭異朵纷,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)永脓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門袍辞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人常摧,你說我怎么就攤上這事搅吁。” “怎么了落午?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵谎懦,是天一觀的道長。 經(jīng)常有香客問我溃斋,道長界拦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任梗劫,我火速辦了婚禮享甸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘梳侨。我一直安慰自己蛉威,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布猫妙。 她就那樣靜靜地躺著瓷翻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪割坠。 梳的紋絲不亂的頭發(fā)上齐帚,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音彼哼,去河邊找鬼对妄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛敢朱,可吹牛的內(nèi)容都是我干的剪菱。 我是一名探鬼主播摩瞎,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼孝常!你這毒婦竟也來了旗们?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤构灸,失蹤者是張志新(化名)和其女友劉穎上渴,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喜颁,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡稠氮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了半开。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片隔披。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖寂拆,靈堂內(nèi)的尸體忽然破棺而出奢米,到底是詐尸還是另有隱情,我是刑警寧澤漓库,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布恃慧,位于F島的核電站,受9級(jí)特大地震影響渺蒿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜彪薛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一茂装、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸勾习。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽其爵。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間侨歉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工揩魂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留幽邓,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓火脉,卻偏偏與公主長得像牵舵,于是被迫代替她去往敵國和親柒啤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容