现在的位置: 首页 > 综合 > 正文

监视文件修改

2013年05月23日 ⁄ 综合 ⁄ 共 9106字 ⁄ 字号 评论关闭

今天在改进文件监视程序时写的框架代码,监视文件修改(采用完成端口和ReadDirectoryChangesW同时在一个线程中监视多个目录,并且能够判断文件是否完全复制完毕)

 

#define STRICT

 

 

#define WINVER               0x0500

#define _WIN32_WINNT 0x0500

#define _WIN32_IE           0x0501

#define _RICHEDIT_VER 0x0200

 

#define _WIN32_DCOM

 

 

#include <CTL/CTL_BASE.HPP>

 

 

class P2PFileShare

{

       typedef struct

       {

              OVERLAPPED   ov;

 

              BYTE           buff[1024];

 

              LPTSTR              path;

              DWORD             flag;

 

              HANDLE            handle;

       }PATH_OV, *LPPATH_OV;

 

       typedef struct

       {

              LPTSTR       name;     // 文件名称

              DWORD      time;       // 通知时间

       }FILE_NOTIFY;

 

public:

       P2PFileShare()

       : mh_IOCP(NULL)

       , mn_OVPtr(0)

       , mp_OVPtr(NULL)

       , mn_Notify(0)

       , mp_Notify(NULL)

       {

       }

 

       virtual~P2PFileShare()

       {

              Close(TRUE);

       }

private:

       // 创建工作线程

       HRESULT                         _CreateWorkerThread();

 

       // 工作线程

#ifndef _WIN32_WCE

       static UINT WINAPI _WorkerThreadProc(IN LPVOID pData);

#else

       static DWORD WINAPI   _WorkerThreadProc(IN LPVOID pData);

#endif     // #ifndef _WIN32_WCE

              HRESULT           _WorkerThreadProc();

 

public:

       HRESULT           Start();

       VRESULT           Close(IN CONST BOOL bWait = FALSE);

public:

       // 监视指定目录

       HRESULT MonitorPath(IN LPCTSTR sFileName);

       // 文件变化通知

       LPTSTR       GetNotify();

private:

       HANDLE                   mh_IOCP;

 

       MLONG                     mn_OVPtr;

       LPPATH_OV*           mp_OVPtr;

 

       MLONG                     mn_Notify;

       FILE_NOTIFYmp_Notify;

public:

       INLINE VRESULT EnterLock() {mo_cs.EnterLock();}

       INLINE VRESULT LeaveLock() {mo_cs.LeaveLock();}

private:

       MTCSObject              mo_cs;

};

 

// 创建工作线程(根据 CPU 的数量,创建相应数量的工作线程)

HRESULT P2PFileShare::_CreateWorkerThread()

{

       HRESULT hr = E_FAIL;

 

       HANDLE hThread;

#ifndef _WIN32_WCE

       if((hThread = (HANDLE)_beginthreadex(NULL, 0

                                          , _WorkerThreadProc

                                          , (LPVOID)this, 0, NULL)) == 0)

       {

              return _doserrno;

       }

#else

       if((hThread = (HANDLE)::CreateThread(NULL, 0

                                          , _WorkerThreadProc

                                          , (LPVOID)this, 0, &NULL)) == 0)

       {

              return ::GetLastError();

       }

#endif

       ::CloseHandle(hThread);     // 关闭句柄避免资源泄漏

       hr = S_OK;

 

       return hr;

}

 

// 工作线程

#ifndef _WIN32_WCE

UINT P2PFileShare::_WorkerThreadProc(IN LPVOID pData)

#else

DWORD P2PFileShare::_WorkerThreadProc(IN LPVOID pData)

#endif     // #ifndef _WIN32_WCE

{

       ((P2PFileShare*)pData)->_WorkerThreadProc();

 

#ifndef _WIN32_WCE

       _endthreadex(0);

#else

       ExitThread(0);

#endif

       return 0;

}

 

// 数据处理线程函数

HRESULT P2PFileShare::_WorkerThreadProc()

{

       // 注意: 调用 GetQueuedCompletionStatus 的线程都将被放到完成端口的等待线程队列中

       // 完成操作循环

 

       BOOL   bSucceed;

       DWORD      dwBytes;

      

       LPDWORD         pCT;

       PATH_OV* pOV;

 

       for(;;)

       {

              bSucceed = ::GetQueuedCompletionStatus(mh_IOCP

                                                                             , &dwBytes

                                                                             , (LPDWORD)&pCT

                                                                             , (LPOVERLAPPED*)&pOV

                                                                             , INFINITE

                                                                             );

              if(bSucceed)

              {

                     if(NULL == pOV) break;          // 退出工作线程

 

                     FILE_NOTIFY_INFORMATION * pfiNotifyInfo = (FILE_NOTIFY_INFORMATION*)pOV->buff;

 

                     DWORD dwNextEntryOffset

                     TCHAR sFileName[1024];

                    

                     do

                     {

                            dwNextEntryOffset = pfiNotifyInfo->NextEntryOffset;

 

                            DWORD dwAction = pfiNotifyInfo->Action

                            DWORD dwFileNameLength = pfiNotifyInfo->FileNameLength;

 

                            CPY_W2T(sFileName, pfiNotifyInfo->FileName, dwFileNameLength/sizeof(WCHAR));

 

                            switch(dwAction)

                            {

                            case FILE_ACTION_REMOVED:         // 文件删除

                                   {

                                          LPTSTR sFullName = new TCHAR[LPTSTRLen(pOV->path) + LPTSTRLen(sFileName) + 1];

                                          if(NULL != sFullName)

                                          {

                                                 LPTSTRCpy(sFullName, pOV->path);

                                                 LPTSTRCat(sFullName, sFileName);

                                                 LPTSTRPrintf(__T("Del %s"n"), sFullName);

 

                                                 delete[] sFullName;

                                          }

                                   }

                                   break;

                            case FILE_ACTION_ADDED:                     // 文件替换

                                   {

                                          // 替换文件时只会触发 FILE_ACTION_ADDED 因此需要手工触发 FILE_ACTION_MODIFIED

                                          LPTSTRPrintf(__T("Add %s"n"), sFileName);

                                   }

                            case FILE_ACTION_MODIFIED:         // 文件修改

                                   {

                                          // 测试文件是否关闭

                                          LPTSTR sFullName = new TCHAR[LPTSTRLen(pOV->path) + LPTSTRLen(sFileName) + 1];

                                          if(NULL != sFullName)

                                          {

                                                 LPTSTRCpy(sFullName, pOV->path);

                                                 LPTSTRCat(sFullName, sFileName);

                                                 HANDLE hFile = ::CreateFile(sFullName

                                                                                           , GENERIC_WRITE

                                                                                           , FILE_SHARE_WRITE

                                                                                           , NULL

                                                                                           , OPEN_EXISTING

                                                                                           , FILE_ATTRIBUTE_NORMAL

                                                                                           , NULL

                                                                                           );

                                                 if(INVALID_HANDLE_VALUE == hFile)

                                                 {

                                                        HRESULT hr = ::GetLastError();

                                                        LPTSTRPrintf(__T("Locked %s %d"n"), sFileName, hr);

                                                 }

                                                 else

                                                 {

                                                        ::CloseHandle(hFile);

 

                                                        LPTSTRPrintf(__T("Modify %s"n"), sFileName);

                                         

                                                        LONG i;

                                                        EnterLock();

                                                        for(i=0;i<mn_Notify;i++)

                                                        {

                                                               if(LPTSTRCompare(mp_Notify[i].name, sFullName) == 0)

                                                               {

                                                                      mp_Notify[i].time = ::GetTickCount();

                                                                      break;

                                                               }

                                                        }

                                                       

                                                        if(i >= mn_Notify)

                                                        {

                                                               FILE_NOTIFY* pNotify = new FILE_NOTIFY[mn_Notify + 1];

                                                               if(NULL != pNotify)

                                                               {

                                                                      if(mn_Notify > 0)

                                                                      {

                                                                             ::CopyMemory(pNotify, mp_Notify, sizeof(FILE_NOTIFY)*mn_Notify);

                                                                             delete[] mp_Notify;

                                                                      }

                                                                     

                                                                      pNotify[mn_Notify].name = sFullName; sFullName = NULL;

                                                                      pNotify[mn_Notify].time = ::GetTickCount();

 

抱歉!评论已关闭.