<p>C# 标准库不提供 Directory.Copy 方法,需手动递归实现:先创建目标目录结构,再逐文件复制,注意路径拼接用 Path.Combine、覆盖设为 true,并处理异常与中断恢复。</p>
用 Directory.Copy?别试了,C# 标准库根本没有这个函数
这是最常踩的坑:搜“c# 复制文件夹”看到一堆带 directory.copy 的伪代码,一粘就报错。.net 原生不提供递归目录拷贝方法,必须自己组合 directory.createdirectory、file.copy 和遍历逻辑。
常见错误现象:CS0117 'Directory' does not contain a definition for 'Copy'
- 所有 .NET 版本(包括 .NET 6/7/8)都不含该 API
- 第三方包如
Microsoft.Extensions.FileSystemGlobbing也不补这个功能 - 别信博客里没贴完整命名空间或版本号的“一行解决”示例
手动递归拷贝:核心是先建目录,再拷文件,顺序不能反
关键逻辑不是“遍历所有文件再挨个复制”,而是“遇到子目录就先创建,再处理其内容”。否则 File.Copy 会因目标路径不存在而抛 DirectoryNotFoundException。
实操建议:
- 用
Directory.GetDirectories和Directory.GetFiles分开获取子目录和文件列表 - 对每个子目录,计算目标路径后调用
Directory.CreateDirectory(它会自动创建中间缺失的父级) - 对每个文件,用
File.Copy(source, destination, overwrite: true),overwrite参数务必显式传true,否则目标存在时直接失败 - 路径拼接统一用
Path.Combine,别用字符串拼接或+
示例片段:
string source = @"C:\src";
string dest = @"D:\backup";
Directory.CreateDirectory(dest); // 确保根目标存在
foreach (string dir in Directory.GetDirectories(source, "*", SearchOption.AllDirectories))
{
string relative = dir.Substring(source.Length + 1);
string targetDir = Path.Combine(dest, relative);
Directory.CreateDirectory(targetDir); // 先建目录
}
foreach (string file in Directory.GetFiles(source, "*.*", SearchOption.AllDirectories))
{
string relative = file.Substring(source.Length + 1);
string targetFile = Path.Combine(dest, relative);
File.Copy(file, targetFile, true); // 覆盖已有文件
}用 FileSystemWatcher 实时同步?小心重复触发和权限问题
如果需求是“源目录变动时自动同步到目标”,别直接套用递归拷贝逻辑监听事件——FileSystemWatcher 的 Created 事件在大文件写入完成前就触发,此时 File.Copy 会因文件被占用而抛 IOException。
使用场景限制:
-
IncludeSubdirectories = true是必须的,但要注意它不会递归监听后续动态创建的子目录(需手动重挂) -
NotifyFilter至少包含NotifyFilters.FileName | NotifyFilters.DirectoryName,否则新建子目录收不到事件 - 避免在事件回调里直接调用耗时操作;加简单延时(如
Task.Delay(100))再检查文件是否真正就绪 - 目标盘符若为网络驱动器或 OneDrive 同步目录,
File.Copy可能静默失败,需捕获UnauthorizedAccessException并记录
.NET 5+ 可用 System.IO.Abstractions 简化测试,但不减少实际代码量
这个包本质是给 File、Directory 等类加了一层接口抽象(如 IFileSystem),方便单元测试模拟文件系统行为。但它不提供新功能,递归拷贝逻辑仍要自己写。
性能与兼容性影响:
- 引入包后编译体积增加约 200KB,纯控制台小工具没必要
- 如果你的项目已用
Microsoft.Extensions.DependencyInjection,注入IFileSystem比直接调静态方法略重,启动慢几毫秒 - 真正省事的是测试环节:可 mock 出“磁盘满”“权限拒绝”等边界情况,而不用真去改系统权限
一句话:它帮你验证逻辑是否健壮,但不帮你少写一行拷贝代码。
递归路径计算和异常恢复是最容易被跳过的部分——比如源路径含中文或特殊符号时 Substring 计算相对路径会出错;又比如中途断电,目标目录只建了一半。真要上生产,得加 try/catch 包裹单个文件操作,并记录失败项供重试。










