在c#下遍历目录,应用最多的应该就是 System.IO.DirectoryInfo.GetDirectories或GetFiles了,但是当目录特别大,文件特别多时,效率不尽人意,此时我们很容易想到三个Win32API函数 FindFirstFile,FindNextFile和FindClose。这三个API搭配使用就能遍历文件和子目录了,而且可以遍历的时候随时中止,避免无谓的操作。在网上搜了一下,发现这方面的文章转载最多的应该就是http://www.cnblogs.com/xdesigner/archive/2006/12/08/586177.html 这篇了,但是按照文中描述的方法,并不能遍历子目录,没办法,就自己想办法,重新写了一个。
以下为源代码:
#region 声明WIN32API函数以及结构 ************************************** [Serializable, System.Runtime.InteropServices.StructLayout (System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Auto ), System.Runtime.InteropServices.BestFitMapping(false)] private struct WIN32_FIND_DATA { public int dwFileAttributes; public int ftCreationTime_dwLowDateTime; public int ftCreationTime_dwHighDateTime; public int ftLastAccessTime_dwLowDateTime; public int ftLastAccessTime_dwHighDateTime; public int ftLastWriteTime_dwLowDateTime; public int ftLastWriteTime_dwHighDateTime; public int nFileSizeHigh; public int nFileSizeLow; public int dwReserved0; public int dwReserved1; [System.Runtime.InteropServices.MarshalAs (System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 260)] public string cFileName; [System.Runtime.InteropServices.MarshalAs (System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName; } [System.Runtime.InteropServices.DllImport ("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)] private static extern IntPtr FindFirstFile(string pFileName, ref WIN32_FIND_DATA pFindFileData); [System.Runtime.InteropServices.DllImport ("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)] private static extern bool FindNextFile(IntPtr hndFindFile, ref WIN32_FIND_DATA lpFindFileData); [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)] private static extern bool FindClose(IntPtr hndFindFile); #endregion //具体方法函数 Stack<string> m_scopes = new Stack<string>(); private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); WIN32_FIND_DATA FindFileData; private System.IntPtr hFind = INVALID_HANDLE_VALUE; void FindFileInDir(string rootDir) { string path = rootDir; start: new FileIOPermission(FileIOPermissionAccess.PathDiscovery, Path.Combine(path, ".")).Demand(); if (path[path.Length - 1] != '\') { path = path + "\"; } Response.Write("文件夹为:"+path+"<br>"); hFind = FindFirstFile(Path.Combine(path,"*"), ref FindFileData); if(hFind!=INVALID_HANDLE_VALUE) { do { if (FindFileData.cFileName.Equals(@".") || FindFileData.cFileName.Equals(@"..")) continue; if ((FindFileData.dwFileAttributes & 0x10) != 0) { m_scopes.Push(Path.Combine(path, FindFileData.cFileName)); } else { Response.Write(FindFileData.cFileName+"<br>"); } } while (FindNextFile(hFind, ref FindFileData)); } FindClose(hFind); if (m_scopes.Count > 0) { path = m_scopes.Pop(); goto start; } } //调用方法如下: FindFileInDir(@"D:");