找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 5449|回复: 5

【C++】多线程全盘文件搜索

[复制链接]
发表于 2014-5-4 21:40:24 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
本帖最后由 Fluray 于 2014-5-5 08:23 编辑

新建一个控制台,要支持MFC。
只用了MFC一个函数AfxBeginThread,其余的全是win API。线程函数修改自《windows程序设计 第2版》 王艳平 张铮 编著
  1. // 多线程文件搜索.cpp : 定义控制台应用程序的入口点。
  2. //

  3. #include "stdafx.h"

  4. #include <afxwin.h>
  5. #include <process.h>
  6. #include <iostream>
  7. #include <stddef.h>

  8. #define BUFSIZE 1024
  9. using namespace std;
  10. //int g_FileName=0;
  11. struct CDirectoryNode : public CNoTrackObject
  12. {
  13.     CDirectoryNode* pNext;  // CTypedSimpleList类模板要使用此成员
  14.     char szDir[MAX_PATH];   // 要查找的目录
  15. };

  16. class CRapidFinder  
  17. {
  18. public:
  19.     CRapidFinder(int nMaxThread);
  20.     virtual ~CRapidFinder();
  21.     BOOL CheckFile(LPCTSTR lpszFileName);

  22.     int m_nResultCount;                             // 结果数目
  23.     int m_nThreadCount;                             // 活动线程数目
  24.     CTypedSimpleList<CDirectoryNode*> m_listDir;    // 目录列表
  25.     CRITICAL_SECTION m_cs;                          // 关键代码段

  26.     const int m_nMaxThread;                 // 最大线程数目
  27.     char m_szMatchName[MAX_PATH];           // 要搜索的文件
  28.     HANDLE m_hDirEvent;                     // 向m_listDir中添加新的目录后置位(受信)
  29.     HANDLE m_hExitEvent;                    // 各搜索线程将要退出时置位(受信)
  30. };
  31. // m_nMaxThread成员是一个const类型的变量,必须使用成员初始化列表来初始化它的值
  32. CRapidFinder::CRapidFinder(int nMaxThread) : m_nMaxThread(nMaxThread)
  33. {
  34.     m_nResultCount = 0;
  35.     m_nThreadCount = 0;
  36.     m_szMatchName[0] = '\0';

  37.     m_listDir.Construct(offsetof(CDirectoryNode, pNext));
  38.     m_hDirEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
  39.     m_hExitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
  40.     ::InitializeCriticalSection(&m_cs);
  41. }

  42. CRapidFinder::~CRapidFinder()
  43. {
  44.     ::CloseHandle(m_hDirEvent);
  45.     ::CloseHandle(m_hExitEvent);
  46.     ::DeleteCriticalSection(&m_cs);
  47. }
  48. //包含此文件名的文件都会被查找到
  49. //BOOL CRapidFinder::CheckFile(LPCTSTR lpszFileName)
  50. //{
  51. //  char string[MAX_PATH];
  52. //  char strSearch[MAX_PATH];
  53. //  strcpy(string, lpszFileName);
  54. //  strcpy(strSearch, m_szMatchName);
  55. //
  56. //  // 将字符串string和strSearch中的字符全部转化成大写
  57. //  _strupr(string);
  58. //  _strupr(strSearch);
  59. //
  60. //  // 找出字符串strSearch在字符串string中第一次出现的位置
  61. //  // 如果string中不包含strSearch,strstr函数返回NULL
  62. //  if(strstr(string, strSearch) != NULL)
  63. //      return TRUE;
  64. //
  65. //  return FALSE;
  66. //}
  67. //必须是相同问文件名(大小写可以不同)
  68. BOOL CRapidFinder::CheckFile(LPCTSTR lpszFileName)
  69. {
  70.     char string[MAX_PATH];
  71.     char strSearch[MAX_PATH];
  72.     strcpy(string, lpszFileName);
  73.     strcpy(strSearch, m_szMatchName);

  74.     // 将字符串string和strSearch中的字符全部转化成大写
  75.     _strupr(string);
  76.     _strupr(strSearch);

  77.     //如果两个文件名称相同
  78.     if(strcmp(string, strSearch) == 0)
  79.         return TRUE;

  80.     return FALSE;
  81. }
  82. UINT FinderEntry(LPVOID lpParam)
  83. {
  84.     CRapidFinder* pFinder = (CRapidFinder*)lpParam;
  85.     CDirectoryNode* pNode = NULL;   // 从m_listDir中取出的节点
  86.     BOOL bActive = TRUE;        // 指示当前线程的状态

  87.     // 循环处理m_listDir列表中的目录
  88.     while(1)
  89.     {
  90.         // 从m_listDir列表中取出一个新的目录
  91.          ::EnterCriticalSection(&pFinder->m_cs);
  92.         if(pFinder->m_listDir.IsEmpty())
  93.         {
  94.             bActive = FALSE;
  95.         }
  96.         else
  97.         {
  98.             pNode = pFinder->m_listDir.GetHead();
  99.             pFinder->m_listDir.Remove(pNode);
  100.         }
  101.         ::LeaveCriticalSection(&pFinder->m_cs);

  102.         // m_listDir为空的话就试图在m_hDirEvent事件上等待
  103.         if(!bActive)
  104.         {
  105.             // 准备进入等待状态
  106.             ::EnterCriticalSection(&pFinder->m_cs);
  107.             pFinder->m_nThreadCount--;
  108.             if(pFinder->m_nThreadCount == 0)  // 查看是否已经查找完毕
  109.             {
  110.                 ::LeaveCriticalSection(&pFinder->m_cs);
  111.                 break;
  112.             }
  113.             ::LeaveCriticalSection(&pFinder->m_cs);

  114.             // 进入等待状态
  115.             ResetEvent(pFinder->m_hDirEvent);
  116.             ::WaitForSingleObject(pFinder->m_hDirEvent, INFINITE);

  117.             // 变成活动线程后进入下一次循环
  118.             ::EnterCriticalSection(&pFinder->m_cs);
  119.             pFinder->m_nThreadCount++;
  120.             ::LeaveCriticalSection(&pFinder->m_cs);
  121.             bActive = TRUE;
  122.             continue;
  123.         }
  124.             
  125.         
  126.         // 在pNode指向的目录中查找文件

  127.         WIN32_FIND_DATA fileData;
  128.         HANDLE hFindFile;
  129.         // 设置成X:\XXXX\*.*的格式
  130.         if(pNode->szDir[strlen(pNode->szDir)-1] != '\\')
  131.             strcat(pNode->szDir, "\");
  132.         strcat(pNode->szDir, "*.*");
  133.         hFindFile = ::FindFirstFile(pNode->szDir, &fileData);
  134.         if(hFindFile != INVALID_HANDLE_VALUE)
  135.         {
  136.             do
  137.             {
  138.                 if(fileData.cFileName[0] == '.')
  139.                     continue;
  140.                 if(fileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
  141.                 {
  142.                     // 将搜索到的目录添加到目录列表中

  143.                     // 为新的节点申请内存空间,设置完整的目录名称
  144.                     CDirectoryNode* p = new CDirectoryNode;
  145.                     strncpy(p->szDir, pNode->szDir, strlen(pNode->szDir)-3);
  146.                     strcat(p->szDir, fileData.cFileName);
  147.                     // 添加到列表中
  148.                     ::EnterCriticalSection(&pFinder->m_cs);
  149.                     pFinder->m_listDir.AddHead(p);
  150.                     ::LeaveCriticalSection(&pFinder->m_cs);
  151.                     // 促使一个“非活动线程”变成“活动线程”
  152.                     ::SetEvent(pFinder->m_hDirEvent);   
  153.                 }
  154.                 else
  155.                 {
  156.                     // 检查搜索到的文件
  157.                     if(pFinder->CheckFile(fileData.cFileName))
  158.                     {
  159.                         ::EnterCriticalSection(&pFinder->m_cs);
  160.                         ::InterlockedIncrement((long*)&pFinder->m_nResultCount);
  161.                         ::LeaveCriticalSection(&pFinder->m_cs);
  162.                           char FileName[256];
  163.                   int  i;
  164.                    for (i=strlen(pNode->szDir)-4;i>=0;i--)
  165.                         FileName[i]=pNode->szDir[i];
  166.                 FileName[strlen(pNode->szDir)-3]='\0';
  167.                 strcat(FileName, fileData.cFileName);
  168.                 printf("%s  \n",FileName);
  169.                     
  170.                     }      
  171.                 }
  172.             }while(::FindNextFile(hFindFile, &fileData));
  173.         }

  174.         // 此节点保存的目录已经搜索完毕,释放内存空间,进入下次循环
  175.         delete pNode;
  176.         pNode = NULL;
  177.     }

  178.     // 促使一个搜索线程从WaitForSingleObject函数返回,并退出循环
  179.     ::SetEvent(pFinder->m_hDirEvent);

  180.     // 判断此线程是否是最后一个结束循环的线程,如果是就通知主线程
  181.     if(::WaitForSingleObject(pFinder->m_hDirEvent, 0) != WAIT_TIMEOUT)
  182.     // 如果此时pFinder->m_hDirEvent所对应的事件对象为受信状态,
  183.     // WaitForSingleObject函数的返回值将是WAIT_OBJECT_0
  184.     {
  185.         // 通知主线程最后一个搜索线程即将退出,文件搜索完毕
  186.         ::SetEvent(pFinder->m_hExitEvent);
  187.    
  188.     }
  189.     return 0;
  190. }


  191. void main()
  192. {

  193.     char szFile[256];
  194.     char szPath[256] ;
  195.     char     szLogicalDriveStrings[BUFSIZE];
  196.     DWORD   iLength;
  197.     int iSub;
  198.     int count=0;
  199.     clock_t start,end;//程序运行的起始和结束时间
  200.     float costtime;//程序耗时
  201.     printf("请输入想查找的文件名:");
  202.     scanf("%s",szFile);
  203.     ZeroMemory(szLogicalDriveStrings, BUFSIZE);
  204.     iLength = GetLogicalDriveStringsA(BUFSIZE-1, szLogicalDriveStrings);
  205.     start=clock();//开始计时
  206.     for(iSub=0; iSub<iLength; iSub+=4)
  207.     {
  208.     CRapidFinder* pFinder = new CRapidFinder(64);
  209.     CDirectoryNode* pNode = new CDirectoryNode;
  210.     //如果不是固定磁盘驱动器:本地硬盘或移动硬盘,忽略
  211.         if(GetDriveType(szLogicalDriveStrings+iSub)!=3)
  212.             continue;
  213.         /*printf("%s  ", szLogicalDriveStrings+iSub);*/
  214.     // 设置参数信息
  215.     strcpy(pNode->szDir, szLogicalDriveStrings+iSub);
  216.     pFinder->m_listDir.AddHead(pNode);
  217.     strcpy(pFinder->m_szMatchName, szFile);

  218.     // 创建辅助线程并等待查找结束
  219.     pFinder->m_nThreadCount = pFinder->m_nMaxThread;
  220.     for(int i=0; i<pFinder->m_nMaxThread; i++)
  221.     {
  222.         AfxBeginThread(FinderEntry, pFinder);
  223.     }
  224.     ::WaitForSingleObject(pFinder->m_hExitEvent, INFINITE);

  225.     // 打印出结果
  226.     /*printf("%s 中最终查找到的文件的个数为:%d \n",szLogicalDriveStrings+iSub, pFinder->m_nResultCount);*/
  227.     count=count+pFinder->m_nResultCount;
  228.     delete pFinder;
  229.     }
  230.     end=clock();//计时结束
  231.     costtime= (float)(end - start) / CLOCKS_PER_SEC;  //转换时间格式
  232.     /*ShellExecute(NULL,"open",g_FileName,NULL,NULL,SW_SHOWNORMAL);*/
  233.     printf("使用64个线程全盘搜索文件%s,一共搜索到%d个,用时%.5f s",szFile,count,costtime);
  234.     system("pause");
  235. }
复制代码


QQ图片20140504213943.jpg
回复

使用道具 举报

发表于 2014-5-12 13:30:05 | 显示全部楼层
楼主 这个只支持 W7?还是通用??
回复 赞! 靠!

使用道具 举报

发表于 2014-7-7 12:54:08 | 显示全部楼层
谢谢楼主分享 正好在写这方面的程序
回复 赞! 靠!

使用道具 举报

发表于 2014-7-30 16:19:59 | 显示全部楼层
感謝大大的分享
回复 赞! 靠!

使用道具 举报

发表于 2017-2-21 19:01:34 | 显示全部楼层
学习了 谢谢分享
回复 赞! 靠!

使用道具 举报

发表于 2017-2-22 10:47:35 | 显示全部楼层
感谢楼主分享
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-22 06:45 , Processed in 0.034885 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表