• 监控文件(夹)的改变


    监控文件(夹)是开发中比较常用的功能.

    Windows API函数FindFirstChangeNotification、FindCloseChangeNotification、

    FindNextChangeNotification可以实现监控文件夹的改变,

    但是不能具体指出改变的是哪个文件,自己写程序比较文件?有点舍本逐末了。个人觉得这些函数有些鸡肋。

    还好ReadDirectoryChangesW能满足这种需求。其声明如下:

    BOOL ReadDirectoryChangesW(
      HANDLE hDirectory,
      LPVOID lpBuffer,
      DWORD nBufferLength,
      BOOL bWatchSubtree,
      DWORD dwNotifyFilter,
      LPDWORD lpBytesReturned,
      LPOVERLAPPED lpOverlapped,
      LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
    );

    其执行方式有同步和异步之分,异步性能较好,但涉及到重叠I/O,稍显复杂,因此下面的封装代码中采用的同步方式,在一个独立的线程中专门检测文件的改变.lpBuffer参数则存放发生事件的文件的列表.代码如下:

    /*
    *  监控特定文件目录的改变信息
    */
    class  CFileSystemMonitor
    {
    public:
        
    /*
        * 文件目录改变的类型
        
    */
        
    enum tagACTION 
        { 
            Added       
    = 1,           //添加了文件/目录
            Removed  = 2,           //删除了文件/目录
            Modified    = 3,             //更改了文件/目录
            Renamed  = 4             //重命名了文件/目录
        };

        
    //定义文件目录改变后的回调函数指针
        typedef  void ( *lpFunDealFile )(  tagACTION action, LPCTSTR lpszFileSrc, LPCTSTR lpszFileDst );

    public:
        CFileSystemMonitor()
        {
            m_hDir           
    =  NULL;
            m_bContinue  
    =  FALSE;
            m_hThread     
    =  NULL;
        }

        
    ~CFileSystemMonitor()
        {}

        
    /*
        * 设置回调函数
        
    */
        
    void  SetDealFilePtr( lpFunDealFile pFunDeal )
        {
            ASSERT( pFunDeal 
    != NULL );
            m_pFunDeal  
    =  pFunDeal;
        }

        BOOL  StartMonitor( LPCTSTR lpszDir )
        {
            ASSERT( m_hThread 
    == NULL );

            HANDLE  hDir 
    =  ::CreateFile( lpszDir, GENERIC_READ|FILE_LIST_DIRECTORY,
                                        FILE_SHARE_READ
    |FILE_SHARE_WRITE|FILE_SHARE_DELETE,NULL, 
                                        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,NULL);
            
    if( INVALID_HANDLE_VALUE == hDir ) 
                
    return FALSE;
            
    this->m_hDir     =  hDir;

            m_bContinue  
    =  TRUE;
            m_hThread     
    =  ::CreateThread( NULL, 0, MonitorProc, this0, NULL );
            
    return ( NULL == m_hThread )?FALSE:TRUE;
        }

        
    void   EndMonitor()
        {
            ASSERT( m_hThread 
    != NULL );
            m_bContinue   
    =  FALSE;
            DWORD  dwRet 
    = ::WaitForSingleObject( m_hThread, 1000 );
            
    if( WAIT_TIMEOUT == dwRet )
            {
                ASSERT( m_hThread 
    != NULL );
                ::TerminateThread( m_hThread, 
    -1 );
            }

            ::CloseHandle( m_hDir );
            m_hDir   
    =  NULL;
            m_hThread  
    =  NULL;
            
        }

        BOOL  IsMoniting()
        {
            
    return m_bContinue;
        }

    private:
        HANDLE   m_hDir;

        
    volatile    BOOL    m_bContinue;

        HANDLE   m_hThread;

        lpFunDealFile  m_pFunDeal;

        
    static DWORD WINAPI  MonitorProc ( LPVOID lParam )
        {
            CFileSystemMonitor
    * pThis = ( CFileSystemMonitor* )lParam;
            ASSERT( pThis 
    != NULL );

            
    char szBuf[ 2 * ( sizeof ( FILE_NOTIFY_INFORMATION ) + MAX_PATH ) ];
            FILE_NOTIFY_INFORMATION
    * pNotify  =  ( FILE_NOTIFY_INFORMATION * )szBuf;
            DWORD dwBytesReturned( 
    0 );

            
    while( pThis->m_bContinue )
            {
                
    if!::ReadDirectoryChangesW( pThis->m_hDir, pNotify, sizeof( szBuf ), TRUE, FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME|
                    FILE_NOTIFY_CHANGE_ATTRIBUTES
    |    FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE|
                    FILE_NOTIFY_CHANGE_LAST_ACCESS
    |FILE_NOTIFY_CHANGE_CREATION|FILE_NOTIFY_CHANGE_SECURITY,
                    
    &dwBytesReturned, NULL,    NULL ) )
                {
                    
    break;
                }
                
    else
                {
                    WCHAR 
    *pszFileDst  =  NULL;
                    WCHAR 
    *pszFileSrc  =  pNotify->FileName;
                    pszFileSrc[ pNotify
    ->FileNameLength/2 ] = L'\0';

                    
    if0 != pNotify->NextEntryOffset )
                    {
                        PFILE_NOTIFY_INFORMATION pNext 
    = (PFILE_NOTIFY_INFORMATION)( ( char* )pNotify + pNotify->NextEntryOffset);
                        pszFileDst  
    = pNext->FileName;
                        pszFileDst[ pNext
    ->FileNameLength/2 ] = L'\0';
                    }
                    
    if( NULL != pThis->m_pFunDeal )
                        pThis
    ->m_pFunDeal( (tagACTION)pNotify->Action, CW2T(pszFileSrc) , CW2T(pszFileDst) );
                }
            }

            
    return 0;
        }
    private:
        CFileSystemMonitor( 
    const CFileSystemMonitor& );
        CFileSystemMonitor 
    operator=const CFileSystemMonitor );
    };
  • 相关阅读:
    快速设置Scrapy随机的IP代理
    快速设置随机的UserAgent
    windows安装flask并创建虚拟环境
    数电和模电比较
    程序员如何写出一份好的文档?
    Qt简介
    基于 Qt的聊天工具
    如何将word组合图形保存成png
    2015电赛点滴
    函数定义
  • 原文地址:https://www.cnblogs.com/fangkm/p/1426526.html
Copyright © 2020-2023  润新知