首页 > 代码库 > 使用完成例程监控文件目录的例子

使用完成例程监控文件目录的例子

由于项目需要实现了一个文件监控服务,期间研究过使用完成例程的方式来监控文件目录。

下面简单的BCB6命令行实现版本。(参考来源 http://bbs.csdn.net/topics/340172813 )

下次补充一个完成端口的版本。

  1 //---------------------------------------------------------------------------  2 // 使用完成例程监控当前文件夹  3 //------------------------------------------------------------------------------  4   5   6   7   8 #include <vcl.h>  9 #pragma hdrstop 10 #include <iostream> 11 using namespace std; 12  13  14 //--------------------------------------------------------------------------- 15  16 #pragma argsused 17  18  19 HANDLE hThreadHandle = NULL ; 20 HANDLE hMonitorDirHandle = NULL; 21 HANDLE hMonitorEventHandle = NULL; 22  23 //这个回调函数,是完成例程的核心 24 //在IO 完成的时候会触发。 25 //然后这个回调函数去设置overlapped->hEvent信号量 26 //使线程能不被阻塞。 27 void CALLBACK FileIOCompletionRoutine(  DWORD dwErrorCode, 28                                         DWORD dwNumberOfBytesTransfered, 29                                         LPOVERLAPPED lpOverlapped) 30 { 31     if(dwErrorCode) 32     { 33         printf("Error Code:%d\r\n",dwErrorCode); 34     } 35     //设置信号量,多线程会得到通知 36     SetEvent(lpOverlapped->hEvent); 37 } 38  39 DWORD WINAPI MonitorThread( LPVOID ) 40 { 41     OVERLAPPED overlapped={0}; 42     DWORD ByteReturn = 0; 43     DWORD BufferLen=10*(sizeof(FILE_NOTIFY_INFORMATION)+MAX_PATH*sizeof(TCHAR)); 44     FILE_NOTIFY_INFORMATION* Buffer= 45         (FILE_NOTIFY_INFORMATION*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,BufferLen); 46  47     while(true) 48     { 49         //简单起见只监控了 修改文件和文件目录 50         if(ReadDirectoryChangesW(hMonitorDirHandle,Buffer,BufferLen,TRUE, 51             FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_FILE_NAME, 52             &ByteReturn,&overlapped,FileIOCompletionRoutine)) 53         { 54             DWORD dwResult; 55             //这个信号一开始没信号的,直到完成例程回调被调用(FileIOCompletionRoutine) 56             dwResult=WaitForSingleObjectEx(hMonitorEventHandle,INFINITE,TRUE); 57             if(dwResult==WAIT_IO_COMPLETION    ) 58             { 59                 FILE_NOTIFY_INFORMATION* notify = Buffer; 60  61                 AnsiString fileName = 62                         WideCharLenToString( 63                             notify->FileName,notify->FileNameLength/2); 64                 do 65                 { 66                     bool blNormal = true; 67                     switch(notify->Action) 68                     { 69                     case FILE_ACTION_ADDED: 70                         { 71                             cout<<"增加了文件"<<fileName.c_str()<<endl; 72                         } 73                         break; 74                     case FILE_ACTION_REMOVED: 75                         { 76                             cout<<"删除了文件"<<fileName.c_str()<<endl; 77                         } 78                         break; 79                     case FILE_ACTION_MODIFIED: 80                         { 81                             cout<<"修改了文件"<<fileName.c_str()<<endl; 82                         } 83                         break; 84                     case FILE_ACTION_RENAMED_OLD_NAME: 85                         { 86                             cout<<"被重名的文件"<<fileName.c_str()<<endl; 87                         } 88                         break; 89                     case FILE_ACTION_RENAMED_NEW_NAME: 90                         { 91                             cout<<"新命名的文件"<<fileName.c_str()<<endl; 92                         } 93                         break; 94                     default:   //有可能已经溢出了! 95                         blNormal = false; 96                         break; 97                     } 98  99                     if(!blNormal)100                     {101                         break;102                     }103                     //将指针偏移offset个字节104                     notify =  notify + notify->NextEntryOffset;105                 }106                 while(notify->NextEntryOffset>0);107            }108            //重新设置信号量,继续阻塞109            ResetEvent(hMonitorEventHandle);110         }111         else112         {113             cout<<"缓冲溢出!"<<SysErrorMessage(GetLastError()).c_str()<<endl;114             break;115         }116     }117     HeapFree(GetProcessHeap(),0,Buffer);118     return 0;119 }120 121 int main(int argc, char* argv[])122 {123     AnsiString mointorDir = ExtractFileDir(Application->ExeName);124 125     hMonitorDirHandle=CreateFile(mointorDir.c_str(),126         FILE_LIST_DIRECTORY,                            //见MSDN ReadDirectoryChangesW 函数说明127         FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,128         NULL,129         OPEN_EXISTING,130         FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED,//FILE_FLAG_OVERLAPPED表示异步模式,当异步的IO 完成的时,会填充OVERLAPPED结构131         NULL);132 133     if(hMonitorDirHandle == INVALID_HANDLE_VALUE)134     {135         cout<<"打开监控文件夹失败!"<< SysErrorMessage(GetLastError()).c_str() <<endl;136         CloseHandle(hMonitorDirHandle);137         return 0;138     }139 140     hMonitorEventHandle = CreateEvent(NULL,TRUE,FALSE,NULL);141 142     DWORD threadId = 0;143     hThreadHandle = CreateThread(NULL,0,MonitorThread,NULL,0,&threadId);144 145 146     cout<<"开始监控本程序所在的文件夹..."<<endl;147     int i=0;148     cin>>i;149 150     CloseHandle(hThreadHandle);151     CloseHandle(hMonitorDirHandle);152     CloseHandle(hMonitorEventHandle);153     return 0;154 }155 //---------------------------------------------------------------------------

 

使用完成例程监控文件目录的例子