C#应用中如何使用Win32 API递归获取含完整路径的目录与文件列表
C#使用Win32 API高速递归遍历目录实现
针对大文件量目录扫描场景,Win32 API相比.NET原生目录操作接口性能更优,可实现数千到上万级文件目录的快速遍历。
需求说明
现有基础实现仅能输出D盘根目录下的文件/文件夹名称,无完整路径,需改造为支持递归遍历所有子文件夹、子文件夹内的所有文件,同时输出完整路径。
依赖枚举与结构体定义
public enum FINDEX_SEARCH_OPS { FindExSearchNameMatch = 0, FindExSearchLimitToDirectories = 1, FindExSearchLimitToDevices = 2 } public enum FINDEX_INFO_LEVELS { FindExInfoStandard = 0, FindExInfoBasic = 1 } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] struct WIN32_FIND_DATA { public uint dwFileAttributes; public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime; public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime; public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; public uint dwReserved0; public uint dwReserved1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName; }
完整递归遍历实现代码
using System; using System.Runtime.InteropServices; using System.IO; class Program { // Kernal32.dll 文件操作相关导入 [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern IntPtr FindFirstFileEx( string lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, out WIN32_FIND_DATA lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, IntPtr lpSearchFilter, int dwAdditionalFlags); [DllImport("kernel32.dll", CharSet = CharSet.Auto)] static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32.dll")] static extern bool FindClose(IntPtr hFindFile); public const int FIND_FIRST_EX_CASE_SENSITIVE = 1; public const int FIND_FIRST_EX_LARGE_FETCH = 2; static void Main() { // 遍历起始路径,可自行修改 string rootPath = @"D:\"; ScanDirectory(rootPath); Console.ReadLine(); } /// <summary> /// 递归扫描指定目录下的所有文件和子目录 /// </summary> /// <param name="directoryPath">要扫描的目录完整路径</param> static void ScanDirectory(string directoryPath) { FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic; int additionalFlags = 0; // Vista及以上系统开启优化参数 if (Environment.OSVersion.Version.Major >= 6) { findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic; // 大批量文件扫描可开启以下参数进一步提升性能 additionalFlags = FIND_FIRST_EX_LARGE_FETCH; } string searchPattern = Path.Combine(directoryPath, "*.*"); WIN32_FIND_DATA findData; IntPtr hFile = FindFirstFileEx( searchPattern, findInfoLevel, out findData, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, additionalFlags); if (hFile.ToInt32() != -1) { do { // 跳过.和..两个系统目录 if (findData.cFileName == "." || findData.cFileName == "..") { continue; } string fullPath = Path.Combine(directoryPath, findData.cFileName); Console.WriteLine("找到条目:{0},属性:{1}", fullPath, findData.dwFileAttributes); // 如果是目录,递归扫描 if ((findData.dwFileAttributes & (uint)FileAttributes.Directory) != 0) { try { ScanDirectory(fullPath); } catch (Exception ex) { // 可根据需要处理无权限访问等异常 Console.WriteLine("扫描目录{0}失败:{1}", fullPath, ex.Message); } } } while (FindNextFile(hFile, out findData)); FindClose(hFile); } } }
功能说明
- 自动跳过
.和..系统默认目录,避免递归死循环 - 遍历到目录时自动触发递归扫描子目录内容
- 输出内容自动拼接完整路径,可直接对应到磁盘上的实际文件/目录位置
- 加入了异常捕获逻辑,可处理无权限访问、系统保留目录等扫描异常场景
- 支持开启
FIND_FIRST_EX_LARGE_FETCH参数,进一步提升大批量文件场景下的扫描速度
内容的提问来源于stack exchange,提问作者MiralShah
相关产品推荐
相关产品推荐

