监控文件(夹)的改变

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

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,  this 0 , 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 ' ;

                
if 0   !=  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 );
};

 

你可能感兴趣的:(文件)