Directory.GetFiles默认不递归,需显式传SearchOption.AllDirectories;权限异常时推荐DirectoryInfo手动递归;大数据量用yield return返回IEnumerable;路径拼接必须用Path.Combine。

Directory.GetFiles 递归遍历最常用,但默认不递归
Directory.GetFiles 是最直接的起点,但它默认只查当前目录,不会进入子文件夹。很多人第一次用就只拿到空数组或漏掉深层文件,就是因为没传 SearchOption.AllDirectories。
正确写法是:
string[] files = Directory.GetFiles(@"C:MyFolder", "*.*", SearchOption.AllDirectories);
注意三点:
-
"*.*"匹配所有带扩展名的文件;若要包含无扩展名文件,改用"*" - 路径末尾不要加反斜杠(
@"C:MyFolder")——虽然多数情况不报错,但某些 .NET 版本下可能触发ArgumentException - 如果目标文件夹权限不足或含符号链接循环,会直接抛
UnauthorizedAccessException或IOException,不能靠返回值判断
用 DirectoryInfo 避免异常中断,适合有权限杂乱的场景
当遍历网络盘、用户文档目录等权限不统一的地方,Directory.GetFiles 一遇到拒绝访问就整个失败。这时改用 DirectoryInfo + 手动递归更可控。
核心思路是捕获每个子目录的访问异常,跳过问题节点继续往下走:
public static List<string> GetAllFilesSafely(string root) {
var result = new List<string>();
var queue = new Queue<DirectoryInfo>();
queue.Enqueue(new DirectoryInfo(root));
<pre class='brush:php;toolbar:false;'>while (queue.Count > 0) {
var dir = queue.Dequeue();
try {
result.AddRange(dir.GetFiles().Select(f => f.FullName));
foreach (var subDir in dir.GetDirectories()) {
queue.Enqueue(subDir);
}
}
catch (UnauthorizedAccessException) { /* 忽略该目录 */ }
catch (DirectoryNotFoundException) { /* 路径已消失,跳过 */ }
}
return result;}
这种写法牺牲一点性能(对象创建多),但稳定性高得多。尤其在 Windows 用户目录(如 C:UsersAliceAppData)里几乎必用。
用 LINQ 和 yield return 做内存友好型遍历
如果文件数量极大(比如上万),一次性加载所有路径到 string[] 或 List<string></string> 容易吃光内存。这时推荐返回 IEnumerable<string></string>,边枚举边处理。
一个轻量级实现:
public static IEnumerable<string> EnumerateAllFiles(string root, string pattern = "*.*") {
foreach (var file in Directory.GetFiles(root, pattern))
yield return file;
foreach (var dir in Directory.GetDirectories(root))
foreach (var file in EnumerateAllFiles(dir, pattern))
yield return file;
}调用时用 foreach 直接消费,不会缓存全部结果:
foreach (string path in EnumerateAllFiles(@"C:Logs")) {
ProcessFile(path); // 比如计算哈希、读取首行、移动归档
}注意:这个版本仍可能因权限问题中断,如需容错,得把每层 GetDirectories 和 GetFiles 都包在 try/catch 里。
Path.Combine 拼接路径,别用字符串拼接
批量处理时经常要从相对路径生成绝对路径,或者组合子目录。新手常写 parent + "\" + child,这在 Linux 容器或跨平台项目里直接出错。
必须用 Path.Combine:
-
Path.Combine(@"C:Data", "2024", "report.txt")→"C:Data‚4 eport.txt" -
Path.Combine("/home/user", "docs", "readme.md")→"/home/user/docs/readme.md"(Linux 下自动用/) - 它会自动清理重复分隔符和冗余
"..",比如Path.Combine("a\", "\b", "..\c")→"ac"
哪怕你 100% 确定只跑 Windows,也别省这个函数——未来某天 CI 流水线切到 GitHub Actions 的 Ubuntu runner 上,就会卡在这儿。


















