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

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

和完成例程比较。完成端口的效率更高。其主要原因是完成端口可以指定线程池。

下面是BCB实现效果及源码(参考资料 windows 核心编程 第10章,11章)

技术分享

 

//---------------------------------------------------------------------------#include <vcl.h>#include <iostream>using namespace std;#pragma hdrstop//---------------------------------------------------------------------------#pragma argsusedHANDLE hMonitorDir = NULL;HANDLE hCompletePort = NULL;const DWORD CompleteKey = 1;//让完成端口处理线程池自己决定最多的线程并发数const DWORD MaxThreadCount = 0;DWORD dwByteReturn;OVERLAPPED overlapped={0};DWORD dwError = 0;int fileCount = 0;//线程池DWORD WINAPI ThreadProc(LPVOID lpParameter){    DWORD dwTranferBytes = 0;    DWORD dwKey = 0;    LPOVERLAPPED pOverLapped = &overlapped;    //捕获文件信息的缓冲长度    DWORD dwBufLen        =2*(sizeof(FILE_NOTIFY_INFORMATION)+MAX_PATH*sizeof(TCHAR));    //捕获文件信息的缓冲buffer    FILE_NOTIFY_INFORMATION* Buffer        =(FILE_NOTIFY_INFORMATION*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwBufLen);    while(true)    {        //完成端口的关键所在        //和完成例程相比,完成端口的优势是可以用线程池来监控IO,效率更高        BOOL blOk = GetQueuedCompletionStatus(hCompletePort,                                &dwTranferBytes,                                &dwKey,                                &pOverLapped,INFINITE);        dwError = GetLastError();        //输出线程编号        cout<<"线程号:"<<GetCurrentThreadId()<<endl;                if(blOk && CompleteKey == dwKey)        {            //捕获到文件变化            FILE_NOTIFY_INFORMATION* notify = Buffer;            AnsiString fileName =                    WideCharLenToString(                        notify->FileName,notify->FileNameLength/2);            do            {                bool blNormal = true;                switch(notify->Action)                {                case FILE_ACTION_ADDED:                    {                        cout<<"增加了文件"<<fileName.c_str()<<endl;                    }                    break;                case FILE_ACTION_REMOVED:                    {                        cout<<"删除了文件"<<fileName.c_str()<<endl;                    }                    break;                case FILE_ACTION_MODIFIED:                    {                        cout<<"修改了文件"<<fileName.c_str()<<endl;                    }                    break;                case FILE_ACTION_RENAMED_OLD_NAME:                    {                        cout<<"被重名的文件"<<fileName.c_str()<<endl;                    }                    break;                case FILE_ACTION_RENAMED_NEW_NAME:                    {                        cout<<"新命名的文件"<<fileName.c_str()<<endl;                    }                    break;                default:   //有可能已经溢出了!                    blNormal = false;                    break;                }                if(!blNormal)                {                    break;                }                //将指针偏移offset个字节                notify =  notify + notify->NextEntryOffset;            }            while(notify->NextEntryOffset>0);            if(!ReadDirectoryChangesW(hMonitorDir,Buffer,dwBufLen,TRUE,                    FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_FILE_NAME ,                    &dwByteReturn,&overlapped,NULL))            {                dwError = GetLastError();                CloseHandle(hMonitorDir);                CloseHandle(hCompletePort);                HeapFree(GetProcessHeap(),0,Buffer);                cout<<"监控文件夹失败! "<<SysErrorMessage(dwError).c_str()<<endl;                break;            }        }        else        {            cout<<"完成端口异常! "<<SysErrorMessage(dwError).c_str()<<endl;            CloseHandle(hMonitorDir);            CloseHandle(hCompletePort);            HeapFree(GetProcessHeap(),0,Buffer);            break;        }    }    return 0;}int main(int argc, char* argv[]){    cout<<"开始监控程序目录!...."<<endl;    AnsiString fileName = "G:\\unireport20\\Report\\Out\\ImageUpload\\2014";//ExtractFileDir(Application->ExeName);    //打开目录    hMonitorDir=CreateFile(fileName.c_str(),        FILE_LIST_DIRECTORY,  //表明打开一个目录        FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,        NULL,        OPEN_EXISTING,        FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED,//FILE_FLAG_OVERLAPPED表示异步模式        NULL);    dwError = GetLastError();    if (INVALID_HANDLE_VALUE =http://www.mamicode.com/= hMonitorDir)    {        cout<<"打开文件目录失败! "<<SysErrorMessage(dwError).c_str()<<endl;        return 0;    }    //创建完成端口    hCompletePort =        CreateIoCompletionPort(hMonitorDir,NULL,CompleteKey,MaxThreadCount);    dwError = GetLastError();    if(NULL == hCompletePort)    {        cout<<"创建完成端口失败! "<<SysErrorMessage(dwError).c_str()<<endl;        CloseHandle(hMonitorDir);        return 0;    }    //捕获文件信息的缓冲长度    DWORD dwBufLen        =2*(sizeof(FILE_NOTIFY_INFORMATION)+MAX_PATH*sizeof(TCHAR));    //捕获文件信息的缓冲buffer    FILE_NOTIFY_INFORMATION* Buffer        =(FILE_NOTIFY_INFORMATION*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwBufLen);    //开始监控文件夹    if(!ReadDirectoryChangesW(hMonitorDir,Buffer,dwBufLen,TRUE,            FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_FILE_NAME,            &dwByteReturn,&overlapped,NULL))    {        dwError = GetLastError();        CloseHandle(hMonitorDir);        HeapFree(GetProcessHeap(),0,Buffer);        cout<<"监控文件夹失败! "<<SysErrorMessage(dwError).c_str()<<endl;    }        //启动线程池,在线程池中进行IO 完成监控    //如果是VISTA 以上级别的操作系统,建议使用    //TrySubmitThreadpoolCallback    //这里,我启用五个工作线程,但实际上完成端口会自己调剂    for(int i = 0; i<5; i++)    {        QueueUserWorkItem(ThreadProc,NULL,0x00000000|0x00000010);    }    int i = 0;    cin>>i;    CloseHandle(hMonitorDir);    CloseHandle(hCompletePort);    HeapFree(GetProcessHeap(),0,Buffer);    return 0;}//---------------------------------------------------------------------------

 

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