由于项目需要实现了一个文件监控服务,期间研究过使用完成例程的方式来监控文件目录。
下面简单的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 ",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 else 112 { 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 //---------------------------------------------------------------------------