最近自己在做一个类似于galgame管理器的东西,于是便接触到了硬盘搜索,MS并没有直接给我们去访问搜索的接口,只是在C#中提供了FindFirstFile和FindNextFile让我们去自己构造算法。网上一些比较高效的算法都是采用这个封装的,我自己写的这套非递归文件遍历算法虽然没有那个那么高效吧···不过算是思路简单,随手一写就能用的,而且效率可以接受,采用的是System.IO下的Directory类自带的一些方法。(在我这台机器上该算法扫描7W文件需要15s的时间)
先贴出源代码:
1 public static void getAllDir(string path) 2 { 3 //文件夹栈,用于消除递归 4 List<string> folders = new List<string>(); 5 6 if (Directory.Exists(path)) 7 { 8 folders.Add(path);//栈初始化 9 10 11 while (folders.Count > 0) 12 { 13 string[] fileList;//文件列表 14 15 //检查该目录是否可以打开,不可以打开直接读取下一个文件夹 16 try 17 { 18 fileList = Directory.GetFileSystemEntries(path); 19 } 20 catch (System.Exception ex) 21 { 22 if (folders.Count > 0)//读取下一个文件夹 23 { 24 folders.RemoveAt(0);//移除目录 25 path = folders[0]; 26 } 27 28 continue; 29 } 30 31 folders.RemoveAt(0);//移除目录 32 33 foreach (string file in fileList) 34 { 35 if (Directory.Exists(file)) 36 { 37 //遇到文件夹就保存文件名以便日后展开 38 folders.Add(file); 39 } 40 else 41 { 42 //文件 43 string fileName = Path.GetFileName("@" + file);//获取文件名 44 45 //判断是否有扩展名 46 if (fileName.LastIndexOf('.') != -1) 47 { 48 string exname = fileName.Substring(fileName.LastIndexOf('.') + 1);//获得扩展名 49 Match exnameMatch = Regex.Match(exname, "(exe|iso|rar)");//正则匹配扩展名 50 if (exnameMatch.Success) 51 { 52 ListViewItem lvi = new ListViewItem(); 53 ListViewItem.ListViewSubItem lvsi = new ListViewItem.ListViewSubItem(); 54 55 //添加第一列(游戏名称) 56 lvi.Text = fileName.Substring(0, fileName.LastIndexOf('.')); 57 lvi.Tag = fileName; 58 59 //添加第二行(游戏路径) 60 lvsi.Text = Path.GetFullPath(file); 61 lvi.SubItems.Add(lvsi); 62 63 //添加到表格中 64 GV.galFileNameGroup.Add(lvi); 65 } 66 } 67 } 68 } 69 if (folders.Count > 0)//读取下一个文件夹 70 path = folders[0]; 71 } 72 } 73 }
整体思路是找到一层后,如果是文件,则判断文件扩展名是否符合规范,符合则加入;如果是文件夹,则进入该层继续判断,直到扫描完所有文件层。在这里我们采用非递归方式,用list来记录目前层中的文件夹,遇到后不是直接进入而是先加入到list中去,等到这层扫完了后再一点点处理list中的文件夹,直到list为空。
这样我们再通过遍历硬盘盘符对每个盘符调用该算法就做到了遍历硬盘:
1 public static void Refresh() 2 { 3 //清空内容 4 GV.galFileNameGroup = new List<ListViewItem>(); 5 6 //扫描盘符并遍历所有硬盘分区 7 DriveInfo[] dr = DriveInfo.GetDrives(); 8 foreach (DriveInfo di in dr) 9 { 10 if (di.IsReady) 11 getAllDir(di.ToString()); 12 } 13 }