查小范围用 directory.getfiles,查大目录必须用 directory.enumeratefiles;前者一次性加载全部路径,后者延迟执行、节省内存;全盘扫描需处理驱动器就绪性、权限异常、符号链接、长路径及文件编码等问题。

用 Directory.GetFiles 还是 Directory.EnumerateFiles?
直接回答:查小范围、要立刻拿到全部结果,用 Directory.GetFiles;查大目录(比如全盘)、怕卡死或内存爆掉,必须用 Directory.EnumerateFiles。前者返回 string[],一次性加载所有路径进内存;后者返回 IEnumerable<string></string>,边遍历边 yield,延迟执行——这对 C:\ 这种上万文件的目录几乎是刚需。
-
SearchOption.AllDirectories会递归,但遇到权限不足的文件夹(如C:\Windows\System32)会直接抛UnauthorizedAccessException,不加 try/catch 就崩 - 想跳过符号链接(symlink)或挂载点(reparse point),得手动检查:
if ((File.GetAttributes(path) & FileAttributes.ReparsePoint) == 0) - 搜索模式如
"*.log"不支持正则,只支持通配符;想模糊匹配文件名含"error_2026"的,得靠.Contains()或Regex.IsMatch()后过滤
全盘扫描必须处理驱动器和权限问题
调 DriveInfo.GetDrives() 拿到所有盘符后,不能直接开扫。NTFS 卷上的系统保护目录(C:\Recovery、C:$Recycle.Bin)、加密卷、或 BitLocker 锁定盘会拒绝访问——不是代码写错了,是 Windows 就不让你进。
- 先过滤掉非就绪/不可读驱动器:
drive.IsReady && drive.DriveType == DriveType.Fixed - 对每个盘根目录做
try/catch (UnauthorizedAccessException),捕获后跳过,别让整个扫描停摆 - 避免用
Directory.GetFiles(root, "*.*", SearchOption.AllDirectories)扫根目录——它会在进第一个子目录前就尝试读取所有子项,极易触发权限异常 - 推荐组合:
Directory.EnumerateDirectories(root, "*", SearchOption.TopDirectoryOnly)先拿一级子目录,再逐个安全递归
文件内容搜索不能靠 File.ReadAllText 硬刚
用 File.ReadAllText(fileName) 读每个文件再 .Contains(),看似简单,实则三处致命伤:二进制文件(PDF/DOCX)会乱码报错;超大日志文件(>500MB)直接 OOM;编码未知时(如 GBK 的文本)读出来全是问号。
- 先判断文件是否可读为文本:
Path.GetExtension(fileName).ToLowerInvariant() is ".txt" or ".log" or ".cs" or ".xml" - 读取时指定编码,优先
Encoding.UTF8,失败再 fallback 到Encoding.Default(即系统 ANSI) - 对 Word/PDF/Excel 等格式,必须走专用库(如
FreeSpire.Doc、itext7、EPPlus),Windows Search API(Microsoft.Search.Interop)虽快但需系统开启索引服务,且部署受限 - 别在 UI 线程里跑全文搜——用
Task.Run()包一层,否则界面直接冻结
实际项目中容易被忽略的边界点
真实环境里,最常栽跟头的不是语法,而是路径语义和并发干扰。
-
Directory.GetFiles(@"C:\temp", "*.config")可能漏掉C:\temp\sub\app.config——因为没传SearchOption.AllDirectories - 多线程并行扫描不同盘符时,若共用一个
List<string></string>收集结果,不加锁或不用ConcurrentBag会导致数据丢失 - 长路径(>260 字符)在旧版 .NET Framework 默认被截断,.NET Core/.NET 5+ 需在
app.manifest中启用longPathAware=true,否则Directory.EnumerateFiles直接跳过那些路径 - 搜索时用户可能正在删/改文件,
FileNotFoundException和DirectoryNotFoundException必须捕获,不能当异常处理,得当“正常现象”吞掉










