• 应用重叠I/O模型异步监控文件(夹)


    小弟之前有篇关于监控文件(夹)的文章,利用的是API函数ReadDirectoryChangesW,当时图方便啊,使用ReadDirectoryChangesW进行同步监控文件(夹),现在突然发现自己居然没有手段让运行阻塞的ReadDirectoryChangesW函数的线程正常地退出,继而导致很多资源无法释放,恼火了.无奈之下只好又写了异步的版本。思考再三,由于监控过程不存在可收缩性的考虑,也就没有使用完成端口模型,使用重叠I/O模型就足够了。
    //.h文件
    /*

    * 投送操作数据
    */
    typedef 
    struct _SPerIOData
    {
        OVERLAPPED                           m_overlapped;   
    //重叠结构
        FILE_NOTIFY_INFORMATION*  m_pNotify; 
        CHAR                                      m_szBuffer[ 
    2 * ( sizeof ( FILE_NOTIFY_INFORMATION ) + MAX_PATH ) ];
        DWORD                                   m_dwBytesReturned;

        
    void  Init( HANDLE hEvent )
        {
            
    //使用AcceptEx函数需要事先创建连接套件字
            m_overlapped.Internal = 0;
            m_overlapped.InternalHigh 
    = 0;
            m_overlapped.Offset 
    = 0;
            m_overlapped.OffsetHigh 
    = 0;
            m_overlapped.hEvent 
    = hEvent;

            m_pNotify  
    =  ( FILE_NOTIFY_INFORMATION * )m_szBuffer;
            m_dwBytesReturned  
    =  0;

            ZeroMemory( m_pNotify,  _countof( m_szBuffer ) );
        }
    }SPerIOData, 
    *PSPerIOData;
    /////////////////////////////////////////////////////////////////////////////////

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

    private:
        HANDLE   m_hEvent;  
    //事件句柄
        HANDLE   m_hDir;      //文件(夹)句柄
        HANDLE   m_hThread; //监控线程句柄

        
    volatile    BOOL  m_bContinue;  //指示监控线程是否继续

        SPerIOData  m_perIOData;  
    //监控投送数据

    public:
        CFileSystemMonitor();
        
    ~CFileSystemMonitor();
        
        
    /*
        * 开始监控文件(夹)
        * lpszDir: 要监控的文件(夹)
        * 返回成败与否
        
    */
        BOOL  StartMonitor( LPCTSTR lpszDir );

        
    /*
        * 停止监控
        
    */
        
    void   EndMonitor();

    private:
        
    //监控线程
        static DWORD WINAPI  MonitorProc ( LPVOID lParam );
        
    //等待结束线程
        static DWORD WINAPI  WaitExitProc ( LPVOID lParam );

    private:
        CFileSystemMonitor( 
    const CFileSystemMonitor& );
        CFileSystemMonitor 
    operator=const CFileSystemMonitor );
    };

    ////////////////////////////////////////////////////////////////////////////////////////////////////////
    //.cpp文件
    TCHAR *szFileAction[5= { _T("空操作"), _T("添加文件"), _T("删除文件"), _T("修改文件"), _T("重命名文件") };


    CFileSystemMonitor::CFileSystemMonitor()
    {
        
    //初始化数据
        m_hThread  =  NULL;
        m_hEvent  
    =  ::CreateEvent( NULL, FALSE, FALSE, NULL );
        m_perIOData.Init( m_hEvent );

        m_bContinue  
    =  FALSE;
    }

    CFileSystemMonitor::
    ~CFileSystemMonitor()
    {
        ATLASSERT( m_hThread 
    == NULL );
        ::CloseHandle( m_hEvent );
    }

    BOOL CFileSystemMonitor::StartMonitor( LPCTSTR lpszDir )
    {
        ATLASSERT( m_hThread 
    == NULL );

        
    //打开文件(夹),
        HANDLE  hDir =  ::CreateFile( lpszDir, GENERIC_READ|FILE_LIST_DIRECTORY,      //需指定FILE_LIST_DIRECTORY属性
            FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,NULL, 
            OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS
    |FILE_FLAG_OVERLAPPED, NULL );   //指定FILE_FLAG_OVERLAPPED在于使用重叠I/O
        if( INVALID_HANDLE_VALUE == hDir ) 
            
    return FALSE;
        
    this->m_hDir     =  hDir;

        
    //创建监控线程
        this->m_bContinue   =  TRUE;
        m_hThread     
    =  ::CreateThread( NULL, 0, MonitorProc, this0, NULL );
        
    if( m_hThread  == NULL )
            
    return FALSE;


        
    //投送监测操作
        ZeroMemory( m_perIOData.m_pNotify,  _countof( m_perIOData.m_szBuffer ) );
        
    if!::ReadDirectoryChangesW( this->m_hDir, m_perIOData.m_pNotify, sizeof( m_perIOData.m_szBuffer ), 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,
            
    &m_perIOData.m_dwBytesReturned,  (LPOVERLAPPED)&m_perIOData.m_overlapped,    NULL ) )
        {
            
    return FALSE;
        }

        
    return TRUE;
    }


    void  CFileSystemMonitor::EndMonitor()
    {
        
    this->m_bContinue  =  FALSE;
        ::SetEvent( m_hEvent );  
    //人工使事件受信,从而使监控线程退出

        
    //等待结束
        HANDLE hThread     =  ::CreateThread( NULL, 0, WaitExitProc, this0, NULL );
        ::CloseHandle( hThread );
    }

    DWORD WINAPI  CFileSystemMonitor::MonitorProc ( LPVOID lParam )
    {
        CFileSystemMonitor
    * pThis = ( CFileSystemMonitor* )lParam;
        ATLASSERT( pThis 
    != NULL );

        
    while ( pThis->m_bContinue )
        {
            
    //等待事件受信
            ::WaitForSingleObject( pThis->m_hEvent, INFINITE );
            
            
    //调用GetOverlappedResult获取投递操作结果(由于此环境下是单投递操作,故此过程可以省略)
            DWORD  dwTransferred(0);
            
    if!::GetOverlappedResult( pThis->m_hDir, (LPOVERLAPPED)&pThis->m_perIOData.m_overlapped, &dwTransferred, FALSE )  )
            {
                
    break;
            }

            WCHAR 
    *pszFileDst  =  NULL;
            WCHAR 
    *pszFileSrc  =  pThis->m_perIOData.m_pNotify->FileName;
            pszFileSrc[ pThis
    ->m_perIOData.m_pNotify->FileNameLength/2 ] = L'\0';

            
    if0 !=  pThis->m_perIOData.m_pNotify->NextEntryOffset )
            {
                PFILE_NOTIFY_INFORMATION pNext 
    = (PFILE_NOTIFY_INFORMATION)( ( char* ) pThis->m_perIOData.m_pNotify +  pThis->m_perIOData.m_pNotify->NextEntryOffset);
                pszFileDst  
    = pNext->FileName;
                pszFileDst[ pNext
    ->FileNameLength/2 ] = L'\0';
            }

            {
                
    //在输出窗口输出,用户在此可定制自己的处理
                
    //pThis->m_perIOData.m_pNotify->Action 为操作类型
                
    //pszFileSrc为源文件
                
    //pszFileDst为改动后的文件
                TCHAR szOutput[1024];
                wsprintf( szOutput,  _T(
    "%s: 源文件:%s  \n"), 
                                                szFileAction[(tagACTION)pThis
    ->m_perIOData.m_pNotify->Action],
                                                CW2T(pszFileSrc) );
                ::OutputDebugString( szOutput );
            }

            
    //继续投送监测操作
            ZeroMemory( pThis->m_perIOData.m_pNotify,  _countof( pThis->m_perIOData.m_szBuffer ) );
            
    if!::ReadDirectoryChangesW( pThis->m_hDir, pThis->m_perIOData.m_pNotify, sizeof( pThis->m_perIOData.m_szBuffer ), 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,
                
    &pThis->m_perIOData.m_dwBytesReturned,  (LPOVERLAPPED)&pThis->m_perIOData.m_overlapped,    NULL ) )
            {
                
    break;
            }
        }
        
    return 0;
    }

    DWORD WINAPI  CFileSystemMonitor::WaitExitProc ( LPVOID lParam )
    {
        CFileSystemMonitor
    * pThis = ( CFileSystemMonitor* )lParam;
        ATLASSERT( pThis 
    != NULL );

        
    //等待监听线程结束
        ::WaitForSingleObject( pThis->m_hThread, INFINITE );
        pThis
    ->m_hThread  =  NULL;
        
    //关闭文件句柄
        ::CloseHandle( pThis->m_hDir );

        
    return 0;
    }
  • 相关阅读:
    字符编码及文件处理
    列表、元祖、字典及集合的内置方法
    数字类型、字符串及列表的内置方法
    流程控制(if while for)
    一些基本概念及数据类型
    编程语言的发展及变量
    python 入门基本知识
    叁拾贰(转)
    叁拾壹
    叁拾
  • 原文地址:https://www.cnblogs.com/fangkm/p/1537835.html
Copyright © 2020-2023  润新知