linux下c++实现文件监控

HotSwitchDict.h

#ifndef _HOTSWITCH_DICT_H_
#define _HOTSWITCH_DICT_H_
#include <string>
#include <pthread.h>
#include <unistd.h>
#include <fstream>
#include <sys/stat.h>
#include <iostream>
#include <time.h>
#include <stdint.h>

using std::string;
using std::cerr;
using std::endl;
using std::cout;

namespace hsd {

/**
 * @brief 获取当前时间
 */
inline string _getCurrentTime()
{
    time_t t = time(NULL);
    /*本地时间:日期,时间 年月日,星期,时分秒*/
    struct tm* c_t = localtime(&t);
    char buf[20];
    sprintf(buf, "%d-%d-%d %d:%d:%d", c_t->tm_year+1900, c_t->tm_mon, 
                    c_t->tm_mday, c_t->tm_hour, c_t->tm_min, c_t->tm_sec);
    return string(buf);
}

template <class DictType> class HotSwitchDict;

template <class DictType> 
void* monitorThread(void *arg)
{
    HotSwitchDict<DictType> * pHotDict = (HotSwitchDict<DictType>*)arg;
    bool needSleep = false;
    uint32_t curSleepTime = 0;    

    // 检测是否需要停止检测
    while( !pHotDict->m_stopMonitor )
    {
        if( needSleep ) {
            if( curSleepTime++ < pHotDict->m_sleepTime ) {
                sleep(1);
                continue;
            }
            else {
                needSleep = false;
                curSleepTime = 0;
            }
        }
        // 检测pHotDict->m_pSwitchDict是否不为空 2012-08-12
        // 不为空,判断是否到底备用词典的延迟生命周期
        if( pHotDict->m_pSwitchDict != NULL ) {
            delete pHotDict->m_pSwitchDict;
            pHotDict->m_pSwitchDict = NULL;
        }
        // 检测新文件是否到来
        if(pHotDict->isNewDictArrived())
        {
            // 构造新的DictType类型指针
            pHotDict->m_pSwitchDict = 
                    pHotDict->newDictFunc(pHotDict->getNewDictFileName());
            // 判断词典是否加载成功
            if(pHotDict->m_pSwitchDict == NULL) {
                cerr << "[WARNING] [" << _getCurrentTime() << 
                            "] Error when load new Dictionary!" << endl;
            }
            else {
                // 加读锁后,交换m_pCurDict和m_pSwitchDict指针
                DictType * pDictTemp = pHotDict->m_pCurDict;
                pthread_rwlock_wrlock(&pHotDict->m_rwLock);
                pHotDict->m_pCurDict = pHotDict->m_pSwitchDict;
                // 不在删除,直接将m_pSwitchDict指向原来的内存空间
                // 保证指针不删除原来m_pCurDict的指针
                pHotDict->m_pSwitchDict = pDictTemp;
                pthread_rwlock_unlock(&pHotDict->m_rwLock);
                //  delete pDictTemp;
                // 修改当前内存中的词典名字
                pHotDict->switchFileName();
                cout << "[INFO] [" << _getCurrentTime() 
                         << "] New Dictionary Switched!" << endl;
            }
            needSleep = true;
        }
        else { // 继续监控
            needSleep = true;
        }
    }
  return NULL;
}

// 默认的词典构建对象函数
template <class DictType>
inline DictType * DefaultNewDictFunc(const string & fileName)
{
    DictType * tmpDict;
    try {
        tmpDict = new DictType(fileName.c_str());
    }
    catch (int e) {
        return NULL;
    }
    return tmpDict;
}

template <class DictType>
class HotSwitchDict
{
    public:
        typedef DictType* (*NewDictFunc)(const string & fileName);
        // 友元函数,需要操作HotSwitchDict的private变量
        friend void * monitorThread<DictType>(void * arg);
        /**
         * @brief HotSwitchDict 构造函数
         * @param fileName 词典的文件名
         * @param flagFile 词典的监控文件,保存新词典的名字和md5码
         * @param sleepTime 每次词典监控的扫描时间间隔
         */
        HotSwitchDict(const string & fileName, const string & flagFile, 
                                    uint32_t sleepTime = 1)
        : m_pCurDict(NULL), m_pSwitchDict(NULL), m_fileName(fileName),
            m_newFileName(""), m_flagFile(flagFile), m_sleepTime(sleepTime), 
            m_stopMonitor(false)
        {
            pthread_rwlock_init(&m_rwLock, NULL);
            m_lastUpdateTime = 0;
            if( sleepTime < 10 || sleepTime > 3600 ) {
                m_sleepTime = 3600;
            }
        }
        /**
         * @brief 初始化函数,用来初始化词典文件以及监控线程
         * @ndf 初始化词典的函数指针
         * @return 如果初始化不成功,返回false 
         */
        bool init(NewDictFunc ndf)
        {
            this->setNewDictFunc(ndf);
            m_pCurDict = newDictFunc(m_fileName);
            if( m_pCurDict == NULL ) {
                return false;
            }
            int err = pthread_create(&m_monitorThread, NULL, 
                                                monitorThread<DictType>, (void*)this);
            if( err != 0 ) return false;
            return true;
        }
        /**
         * @brief 销毁对象,等待监控xiancheng结束,销毁dict指针和读写锁
         * todo 屏蔽继承
         */
        ~HotSwitchDict() 
        {
            if( m_pCurDict != NULL )
            {
                m_stopMonitor = true;
                // 取消线程,避免出现sleep时间过长,导致join需要大量时间
                //pthread_cancel(m_monitorThread);
                // 等待监控线程结束
                pthread_join(m_monitorThread, NULL);
                // 销毁对象
                delete m_pCurDict;
            }
            m_pCurDict = NULL;
            if( m_pSwitchDict != NULL ) {
                delete m_pSwitchDict;
                m_pSwitchDict = NULL;
            }
            // 销毁锁
            pthread_rwlock_destroy(&m_rwLock);
        }
        /**
         * @brief 获取当前dict的指针
         */
        DictType * getCurDict()
        {
            return m_pCurDict;
        }
        /**
         * @brief 加读锁
         */
        int32_t rwlock_read_lock()
        {
            return pthread_rwlock_rdlock(&m_rwLock);
        }
        /**
         * @brief 加写锁
         */
        int32_t rwlock_write_lock()
        {
            return pthread_rwlock_wrlock(&m_rwLock);
        }
        /**
         * @brief 解开锁 
         */
        int32_t rwlock_unlock()
        {
            return pthread_rwlock_unlock(&m_rwLock);
        }
    private:
        HotSwitchDict() {}
        /**
         * @brief 根据词典文件创建新的dict指针
         */
        DictType * newDictFunc(const string & fileName)
        {
            return m_newDictFunc(fileName.c_str());
        }
        /**
         * @brief 判断新词典文件是否存在
         */
        bool isNewDictArrived()
        {
            // 读取finish文件,得到新词典对应的文件名
            if( access(m_flagFile.c_str(), F_OK|R_OK) < 0 )
            {
                cerr << "[WARNING] [" << _getCurrentTime() << "] flagFile " 
                         << m_flagFile << " not exist or not readable" << endl;
                return false;
            }
            // 如果文件修改时间比m_lastUpdateTime大,则读取文件
            struct stat buf;
            if( stat(m_flagFile.c_str(), &buf) < 0 ) {
                return false;
            }
            time_t flagFileTime = buf.st_ctime;
            if( flagFileTime <= m_lastUpdateTime )
            {
#ifdef DEBUG
                cout << "[DEBUG] flagFileTime is smaller than m_lastUpdateTime" << endl;
#endif
                return false;
            }
            std::ifstream in(m_flagFile.c_str());
            if( !in.is_open() ) {
                cerr << "[ERROR] [" << _getCurrentTime() << "] flagFile " 
                         << m_flagFile << " opened failed" << endl;
                return false;
            }
            string newfileName;
            in >> newfileName;
            in.close();
            // 判定新文件名是否发生变化
            if( newfileName == m_fileName ) {
#ifdef DEBUG
                cout << "[DEBUG] newfileName == m_fileName" << endl;
#endif
                return false;
            }
            // 判断新文件是否存在,使用绝对路径
            if( access(newfileName.c_str(), F_OK|R_OK) < 0 )
            {
                cerr << "[WARN] [" << _getCurrentTime() << "] newfileName " 
                         << newfileName << " not exist or not readable" << endl;
                return false;
            }
            // 保存md5码,并进行验证
            m_newFileName = newfileName;
            m_lastUpdateTime = flagFileTime;
#ifdef DEBUG
            cout << "[DEBUG] [" << _getCurrentTime() << 
                     "] change m_newFileName to " << m_newFileName << endl;
#endif
            return true;
        }
        string getNewDictFileName()
        {
            return m_newFileName;
        }
        /**
         * @brief 当前词典的文件名修改
         */
        void switchFileName()
        {
            m_fileName = m_newFileName;
            m_newFileName = "";
        }
        /**
         * @brief 设置从一个文件初始化DictType*类型的函数
         */
        void setNewDictFunc(NewDictFunc ndf)
        {
            m_newDictFunc = ndf;
        }
    private:    
        DictType * m_pCurDict;
        DictType * m_pSwitchDict;
        string m_fileName;
        string m_newFileName;
        string m_flagFile;
        uint32_t m_sleepTime;
        pthread_rwlock_t m_rwLock;
        pthread_t m_monitorThread;
        bool m_stopMonitor;
        NewDictFunc m_newDictFunc;
        time_t m_lastUpdateTime;
};
}
#endif // _HOTSWITCH_DICT_H_

main.cpp

#include "HotSwitchDict.h"
#include<iostream>
#include<string>
#include<fstream>
#include<map>

using namespace std;
using namespace hsd;

map<string, float>* process_file(const string &file_name)
{
    char s[1000];
    map<string, float> *fea_map;
    fea_map = new map<string, float>;
    fstream f(file_name.c_str());
    f.getline(s, 1000);
    cout<<s<<endl;
    f.close();
    return fea_map;
}


int main()
{
    string f_name, flag_file;
    f_name = "./data/dict.dat";
    flag_file = "./data/dict.dat.md5";

    map<string, float>* (*fun)(const string & fileName);
    HotSwitchDict< map<string, float> > hs(f_name, flag_file, 3);

    fun = process_file;
    hs.init(fun);

    int i = 0;
    while(1);                                                                                           

    return 1;
}

使用方法:
1. 将需要监控的文件路径包括文件名写入flag_file,f_name是实际需要读取的文件。
2. 更新f_name之后,同时更新flag_file中的内容。
3. process_file是监控模块的回调函数,自定义文件处理。

Linux C/C中,可以使用inotify API来监控文件系统的事件。inotify API提供了一种异步的、高效的文件系统事件监控机制,可以监控文件或目录的创建、删除、修改、移动等操作。 使用inotify API需要先创建一个inotify实例,并使用inotify_add_watch函数添加要监控文件或目录。当文件系统中发生对应的事件时,inotify会通知应用程序。 下面是一个简单的例子,演示如何使用inotify API监控文件变化: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/inotify.h> #define EVENT_SIZE ( sizeof (struct inotify_event) ) #define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) int main( int argc, char **argv ) { int length, i = 0; int fd; int wd; char buffer[BUF_LEN]; fd = inotify_init(); if ( fd < 0 ) { perror( "inotify_init" ); } wd = inotify_add_watch( fd, "/tmp", IN_MODIFY | IN_CREATE | IN_DELETE ); while ( 1 ) { i = 0; length = read( fd, buffer, BUF_LEN ); if ( length < 0 ) { perror( "read" ); } while ( i < length ) { struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ]; if ( event->len ) { if ( event->mask & IN_CREATE ) { if ( event->mask & IN_ISDIR ) { printf( "The directory %s was created.\n", event->name ); } else { printf( "The file %s was created.\n", event->name ); } } else if ( event->mask & IN_DELETE ) { if ( event->mask & IN_ISDIR ) { printf( "The directory %s was deleted.\n", event->name ); } else { printf( "The file %s was deleted.\n", event->name ); } } else if ( event->mask & IN_MODIFY ) { if ( event->mask & IN_ISDIR ) { printf( "The directory %s was modified.\n", event->name ); } else { printf( "The file %s was modified.\n", event->name ); } } } i += EVENT_SIZE + event->len; } } ( void ) inotify_rm_watch( fd, wd ); ( void ) close( fd ); exit( 0 ); } ``` 上面的代码中,先使用inotify_init函数创建一个inotify实例,然后使用inotify_add_watch函数添加要监控的目录。在while循环中,使用read函数读取inotify实例中的事件,然后根据事件类型进行相应的处理。最后使用inotify_rm_watch函数移除监控项,关闭inotify实例。 需要注意的是,inotify API只能用于Linux系统,其他操作系统需要使用不同的机制来监控文件系统事件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值