当前位置: 首页 > news >正文

网站制作需要哪些软件单页网站做cpa

网站制作需要哪些软件,单页网站做cpa,综合查询,哈尔滨网站建设的公司哪家好简介 监视指定目录的更改#xff0c;并将有关更改的信息打印到控制台#xff0c;该功能的实现不仅可以在内核层#xff0c;在应用层同样可以。程序中使用 ReadDirectoryChangesW 函数来监视目录中的更改#xff0c;并使用 FILE_NOTIFY_INFORMATION 结构来获取有关更改的信息…  简介 监视指定目录的更改并将有关更改的信息打印到控制台该功能的实现不仅可以在内核层在应用层同样可以。程序中使用 ReadDirectoryChangesW 函数来监视目录中的更改并使用 FILE_NOTIFY_INFORMATION 结构来获取有关更改的信息。 ReadDirectoryChangesW 是Windows提供一个函数它属于Windows API的一部分主要用于监视文件系统中目录的修改、新增、删除等变化并通过回调函数向应用程序提供通知。该API很实用目前市面上已知的所有运行在用户态同步应用都绕不开这个接口。但正确使用该API相对来说比较复杂该接口能真正考验一个Windows开发人员对线程、异步IO、可提醒IO、IO完成端口等知识的掌握情况。 其函数原型为  BOOL WINAPI ReadDirectoryChangesW(_In_ HANDLE hDirectory,_Out_ LPVOID lpBuffer,_In_ DWORD nBufferLength,_In_ BOOL bWatchSubtree,_In_ DWORD dwNotifyFilter,_Out_opt_ LPDWORD lpBytesReturned,_Inout_opt_ LPOVERLAPPED lpOverlapped,_In_opt_ LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ); hDirectory要监视的目录的句柄。lpBuffer接收变更通知的缓冲区。nBufferLength缓冲区的大小。bWatchSubtree如果为 TRUE则监视目录树中的所有目录。如果为 FALSE则仅监视指定的目录。dwNotifyFilter指定要监视的变更类型可以是文件夹或文件的新增、删除、修改等。lpBytesReturned返回实际读取到的字节数。lpOverlapped用于异步操作的 OVERLAPPED 结构。lpCompletionRoutine指定一个回调函数在异步操作完成时调用。 由于该函数提供了丰富的调用方式包括同步和异步方式。异步方式可以采用以下三种方式获取完成通知 在OVERLAPPED结构中的hEvent成员中设置一个事件句柄使用GetOverlappedResult 获取完成结果。使用可提醒IO, 在参数lpComletionRoutine指定一个回调函数。当ReadDirectoryChangesW异步请求完成时驱动会将指定的回调函数(lpComletionRoutine)投递到调用线程的APC队列中。对可提醒IOOVERLAPPED结构中的hEvent 字段操作系统并不使用我们可以自己使用该值。使用IO完成端口通过GetQueuedComletionStatus获取完成结果。 同步方式比较简单但不具可伸缩性在实际应用中并不多。不同的异步方式也影响到线程模型的选择所以如何正确使用该函数其实并不容易。 使用可提醒IO 可提醒IO是异步IO的一种为了支持可提醒IO, Windows为线程都增加了一个基础设施——APC异步过程调用即每个线程都有一个APC队列。当线程处理于可提醒状态时系统会检测该线程的APC队列是否为空如果不会空系统会依次取出队列中的APC进程调用。 采用可提醒IO时需要设置一个完成回调函数ReadDirectoryChangesW。当发起异步IO请求后调用线程不会被阻塞系统会将该异步请求交给驱动程序驱动程序将该请求加入到请求队列中当异步请求完成时驱动程序会将完成回调函数加入到发起线程的APC队列中当发起线程处于可提醒状态时该完成回调函数就会被执行。 Windows提供了6个API可以将线程置为可提醒状态分别是 SleepEx、WaitForSingleObjectEx、WaitForMultipleObjectsEx、SignalObjectAndWait、GetQueuedCompletionStatusEx、MsgWaitForMultipleObjectsEx。 利用线程的APC队列可以创建一个工作线程该线程采用可提醒IO方式循环等待APC调用当我们在工作线程中发起一个ReadDirectoryChangesW请求时线程被挂起当一个请求完成时会将完成回调函数加入到线程的APC队列中系统检测到APC队列不为空线程会被唤醒并取出APC队列中的一项进行调用当APC队列为空中线程会被再次挂起直到APC队列中出现一项新的项。 读者可能会觉得上面的流程很复杂其实实现很简单复杂的东西都由系统帮我们做了我们使用SleepEx使工作线程变为可提醒状态工作线程代码如下 while (!m_bTerminate || HasOutstandingRequests()){::SleepEx(INFINITE, true);} 有了工作线程帮我们处理完成回调函数的调用我们还需要在该工作线程中发起一个ReadDirectoryChangesW请求在请求时需要指定一个完成回调函数(最后一个参数)。对于倒数第二个参数OVERLAPPED对可提醒IO来讲系统并不关心hEvent所以可以将该参数设计为业务相关的数据进行传递在实现时设置为了一个请求对象的指针(具体参考代码实现)ReadDirectoryChangesW 请求代码如下 BOOL success ::ReadDirectoryChangesW(GetDirectoryHandle(), // handle to directoryGetBuffer(), // read results bufferGetBufferSize(), // length of bufferIsWatchSubTree(), // monitoring optionGetNotifyFilter(), // filter conditionsNULL, // bytes returnedthis, // overlapped bufferFileIoCompletionRoutine); // completion routine 完成回调函数需要我们自己实现原型为 VOID CALLBACK FileIOCompletionRoutine(_In_ DWORD dwErrorCode,_In_ DWORD dwNumberOfBytesTransfered,_Inout_ LPOVERLAPPED lpOverlapped ); 读者可能会疑问怎么让ReadDirectoryChangesW请求在工作线程中执行呢Windows为我们提供了以下API可以将一个APC投递到一个指定线程的APC队列中 DWORD QueueUserAPC(PAPCFUNC pfnAPC,HANDLE hThread,ULONG_PTR dwData ); 有了上面这个利器我们可以很方便的在线程间通信为了简化代码复杂度采用无锁设计我将添加文件夹、读取文件夹变更请求、移除文件夹、结束请求都投递到该工作线程中执行并约定一些类成员变量只能在该线程中访问。 需要注意的是由于我们需要不断监控文件夹的磁盘变更情况所以在FileIOCompletionRoutine中处理完文件夹的变更数据后需要再次发起一次ReadDirectoryChangesW请求这样就形成了一条变更链实现文件夹实时磁盘监控。 使用IO完成端口 IO完成端口是Windows为打造一个出色服务器环境提高应用程序性能而提出的解决方案。关于IO完成端口的背景知识并不是本文的重点不熟悉的读者请自行补充。 ReadDirectoryChangesW 支持采用IO完成端口方式读取文件夹磁盘变更为了简单起见在不考虑线程模型的情况下其流程大概如下 1. 创建一个IO完成端口 2. 打开一个文件夹 3. 将打开的文件夹句柄关联到一个IO完成端口上 4. 发起一次ReadDirectoryChangesW请求 5. 调用GetQueuedCompletionStatus获取完成通知 6. 处理完成通知 7. 关闭文件夹句柄 8. 关闭IO完成端口 在第5步中调用GetQueuedCompletionStatus会阻塞调用线程在实际应用中我们经常会在一个工作线程中调用GetQueuedCompletionStatus。为了实时监控文件夹的磁盘变更我同样会创建一个工作线程且该线程只用于处理IO完成端口的完成通知代码如下 while (1){ULONG_PTR pCompKey NULL;DWORD dwNumberOfBytes 0;OVERLAPPED* pOverlapped NULL;BOOL bRet m_iocp.GetStatus(pCompKey, dwNumberOfBytes, pOverlapped);DWORD dwLastError ::GetLastError();if (bRet){ProcessIocpSuccess(pCompKey, dwNumberOfBytes, pOverlapped);}else{if (!ProcessIocpError(dwLastError, pOverlapped)){break;}}} 工作线程就绪后在做完23步之后仍然需要发起一个ReadDirectoryChangesW请求对于IO完成端口虽然请求并不是一定要在工作线程中执行但我们仍然需要这样做理由是除了简化我们的编程模型之外也能使线程更容易得体地退出稍后会说。 跟可提醒IO不同的是发起一个ReadDirectoryChangesW 请求时IO完成端口会使用OVERLAPPED中的hEvent所以我们不能将其设为一个请求对象的指针而应该设为NULL, 但为了在上下文中传递请求对象指针使用了点技巧即将请求对象继承自OVERLAPPED再将请求对象的指针传入即可具体参考代码另外并不需要再指定完成回调函数如下 BOOL success ::ReadDirectoryChangesW(GetDirectoryHandle(), // handle to directoryGetBuffer(), // read results bufferGetBufferSize(), // length of bufferIsWatchSubTree(), // monitoring optionGetNotifyFilter(), // filter conditionsNULL, // bytes returnedthis, // overlapped bufferNULL); // completion routine 同样我们怎样让ReadDirectoryChangesW请求在工作线程中执行呢幸运的是Windows提供了API BOOL WINAPI PostQueuedCompletionStatus(_In_ HANDLE CompletionPort,_In_ DWORD dwNumberOfBytesTransferred,_In_ ULONG_PTR dwCompletionKey,_In_opt_ LPOVERLAPPED lpOverlapped ); 以上API可以在任何线程中调用将一个和完成键dwCompletionKey关联的数据投递到任何一个调用GetQueuedCompletionStatus的线程当然这里只是我们的工作线程。这使得其它线程可以很容易和工作线程通信。 同样为了简化代码复杂度采用无锁设计仍然将添加文件夹、读取文件夹变更请求、移除文件夹、结束请求都投递到该工作线程中执行并约定一些类成员变量只能在该线程中访问。 如何退出工作线程 取消一个ReadDirectoryChangesW请求可以使用CancelIo或CancelIoEx这两个API的区别是CancelIo只能取消调用线程关联的IO设备而CancelIoEx可以取消指定线程关联的IO设备但CancelIoEx只能在Vista及之后的系统中使用为了让代码能正常工作于XP及以后的系统我使用了CancelIo这也是为什么我在使用IO完成端口的时候也要将请求放到工作线程中去执行的原因。 1. 可提醒IO退出 如上所说CancelIo需要在工作线程中去执行我们先将m_bTerminate设为true, 再调用QueueUserAPC将一个退出请求投递到工作线程中然后在工作线程中调用CancelIO之后系统会将完成回调函数加入到工作线程的APC队列中并且将dwErrorCode设为ERROR_OPERATION_ABORTED当收到该错误时我们释放请求对象占用的系统资源当所有请求对象都释放时工作线程中的while循环结束线程正常退出。 2. IO完成端口退出 和可提醒IO退出方式不同的是GetQueuedCompletionStatus的错误处理稍微复杂一点是采用GetLastError获得同样在收到错误码为ERROR_OPERATION_ABORTED时释放请求对象占用的系统资源当所有请求对象都释放时工作线程中的while循环结束线程正常退出。 代码结构 为了同时支持可提醒IO和IO完成端口异步请求的方式调用ReadDirectoryChangesW, 代码做了一些抽象采用C/S模型。将ReadDirectoryChangesW调用封装到了CReadDirectoryRequest类中根据不同的异步模型派生出CCompletionRoutineRequest和CIoCompletionPortRequest类 同样工作线程封装到了CReadDirectoryServer类中根据不同的异步模型派生出CCompletionRoutineServer和CIoCompletionPortServer类 CReadDirectoryChanges类管理CReadDirectoryServer对象的生命周期并维护一个线程安全的队列用于缓存文件夹的变更数据同时对客户端暴露基本服务接口。框架结构如下图所示 完整代码项目 以下代码中使用CreateThread函数创建一个线程并将MonitorFileThreadProc运行起来此函数使用带有FILE_LIST_directory标志的CreateFile打开指定的目录该标志允许该函数监视目录。并使用ReadDirectoryChangesW函数读取目录中的更改传递一个缓冲区来存储更改并指定要监视的更改类型。 使用WideCharToMultiByte函数将宽字符文件名转换为多字节文件名并将文件名与目录路径连接以获得文件的完整路径。然后该功能将有关更改的信息打印到控制台。 #include stdio.h #include Windows.h #include tlhelp32.hDWORD WINAPI MonitorFileThreadProc(LPVOID lParam) {char *pszDirectory (char *)lParam;BOOL bRet FALSE;BYTE Buffer[1024] { 0 };FILE_NOTIFY_INFORMATION *pBuffer (FILE_NOTIFY_INFORMATION *)Buffer;DWORD dwByteReturn 0;HANDLE hFile CreateFile(pszDirectory, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);if (INVALID_HANDLE_VALUE hFile)return 1;while (TRUE){ZeroMemory(Buffer, sizeof(Buffer));// 设置监控目录回调函数bRet ReadDirectoryChangesW(hFile,Buffer,sizeof(Buffer),TRUE,FILE_NOTIFY_CHANGE_FILE_NAME | // 修改文件名FILE_NOTIFY_CHANGE_ATTRIBUTES | // 修改文件属性FILE_NOTIFY_CHANGE_LAST_WRITE, // 最后一次写入dwByteReturn, NULL, NULL);if (TRUE bRet){char szFileName[MAX_PATH] { 0 };// 将宽字符转换成窄字符,宽字节字符串转多字节字符串WideCharToMultiByte(CP_ACP,0,pBuffer-FileName,(pBuffer-FileNameLength / 2),szFileName,MAX_PATH,NULL,NULL);// 将路径与文件连接成完整文件路径char FullFilePath[1024] { 0 };strncpy(FullFilePath, pszDirectory, strlen(pszDirectory));strcat(FullFilePath, szFileName);switch (pBuffer-Action){case FILE_ACTION_ADDED:{printf(添加: %s \n, FullFilePath); break;}case FILE_ACTION_REMOVED:{printf(删除: %s \n, FullFilePath); break;}case FILE_ACTION_MODIFIED:{printf(修改: %s \n, FullFilePath); break;}case FILE_ACTION_RENAMED_OLD_NAME:{printf(重命名: %s, szFileName);if (0 ! pBuffer-NextEntryOffset){FILE_NOTIFY_INFORMATION *tmpBuffer (FILE_NOTIFY_INFORMATION *)((DWORD)pBuffer pBuffer-NextEntryOffset);switch (tmpBuffer-Action){case FILE_ACTION_RENAMED_NEW_NAME:{ZeroMemory(szFileName, MAX_PATH);WideCharToMultiByte(CP_ACP,0,tmpBuffer-FileName,(tmpBuffer-FileNameLength / 2),szFileName,MAX_PATH,NULL,NULL);printf( - %s \n, szFileName);break;}}}break;}case FILE_ACTION_RENAMED_NEW_NAME:{printf(重命名(new): %s \n, FullFilePath); break;}}}}CloseHandle(hFile);return 0; }int main(int argc, char * argv[]) {char *pszDirectory C:\\;HANDLE hThread CreateThread(NULL, 0, MonitorFileThreadProc, pszDirectory, 0, NULL);WaitForSingleObject(hThread, INFINITE);CloseHandle(hThread);system(start https://www.chwm.vip/?ReadDirectoryChangesW);return 0; }效果演示
http://www.pierceye.com/news/573974/

相关文章:

  • 中企动力做网站一次性付款零基础学室内设计
  • 企炬网站wordpress会员付费插件
  • 在哪里购买虚拟空间建设网站网页设计培训机构培训费
  • 网站建设的色彩搭配做网站赚钱吗 怎么赚
  • 门头沟富阳网站建设西安企业电话
  • 电子商务网站建设概括湘潭专业seo优化推荐
  • 炫彩发光字制作免费网站动漫制作就业方向
  • 阿里巴巴可以做网站吗网站的可用性
  • 云虚拟主机怎么做2个网站装饰工程施工
  • 网站备案查询流程wordpress手机页面没有注册
  • 辽宁城乡建设集团官方网站精品课程网站建设
  • 威海 网站建设个人做网站可以盈利么
  • 机关网站源码网站建设 备案什么意思
  • 做理财的网站有哪些怎么弄数据库备份做网站
  • 网站不接入备案易企互联网站建设
  • 那种网站打不开北京网站建设找华网天下
  • 网站建设seo优化浙江网站名称怎么收录
  • 天津网站制作工具想自己做网站 有免费的吗
  • 宝塔织梦网站建设求网站备案照片
  • 聊城住房和城乡建设厅网站研发项目管理软件
  • 国投集团网站开发杭州网站界面设计
  • 做关于什么的网站莆田网站建设解决方案
  • 湖南长沙做网站那些网站可以做反链
  • 成都金牛网站建设公司高端网站配色
  • 做喜报的网站设计师的工作内容
  • 济南网站建设工作wordpress 资讯
  • 网站调用数据库平台公司名单
  • 移动网站怎么做成都设计公司名字
  • 杭州最好的网站设计公司服务器域名解析
  • 做试用网站的原理塘沽网吧开门了吗