监控文件(夹)的改变

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

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 );
};

 

posted @ 2009-03-31 20:09 孤竹君 阅读(...) 评论(...) 编辑 收藏