DirectoryCopy静默复制需捕获UnauthorizedAccessException等异常、跳过符号链接、用Path.Combine拼接路径、Task.Run隔离I/O、IProgress批量上报进度、预检磁盘空间与硬链接。

用 DirectoryCopy 自定义方法实现静默复制
默认的 Directory.CreateDirectory 和 File.Copy 不提供“整个文件夹静默复制”能力,必须自己封装。关键不是“能不能”,而是“怎么避免弹窗、异常中断、路径越界”。静默的核心是捕获所有可预期异常、跳过权限拒绝项、不依赖 UI 线程。
常见错误现象:UnauthorizedAccessException 直接炸掉;PathTooLongException 在深层嵌套时悄无声息失败;复制中途用户删源文件,FileNotFoundException 未处理导致任务终止。
- 递归遍历用
Directory.EnumerateDirectories和Directory.EnumerateFiles(比GetDirectories更省内存,适合大目录) - 目标路径用
Path.Combine拼接,别字符串拼接——Windows 路径分隔符不统一会出错 - 对每个
File.Copy加try/catch,只吞UnauthorizedAccessException和IOException(如正在被占用),其他异常该抛还抛 - 跳过符号链接(
File.GetAttributes判断FileAttributes.ReparsePoint),否则可能无限递归或跨卷复制失控
后台线程里调用 Task.Run 而不是 BackgroundWorker
.NET Core / .NET 5+ 环境下,BackgroundWorker 已废弃,且它本质还是同步阻塞式 I/O,无法真正释放主线程。大量数据拷贝卡住 UI 的根本原因是磁盘 I/O 是同步阻塞的,不是线程问题——得靠异步 I/O 或线程池隔离。
使用场景:WinForms/WPF 主界面需要响应按钮点击、进度条更新,同时复制 10GB+ 文件夹。
- 用
Task.Run(() => DirectoryCopy(src, dst))把整个复制逻辑扔进线程池,UI 线程完全不参与 - 别在后台线程里调用
Dispatcher.Invoke频繁更新进度——每复制一个文件就 Invoke 一次,容易堆积消息队列。改用IProgress<int>回调,批量聚合进度(比如每 100 个文件上报一次) - 注意:.NET 6+ 支持
FileStream.CopyToAsync,但仅限单个文件;整个目录仍需手动调度,没有现成的Directory.CopyAsync
FileOptions.Asynchronous 对复制性能几乎没帮助
有人以为加 FileOptions.Asynchronous 就能加速复制,实际不是。这个 flag 只影响 FileStream 构造后是否启用底层异步 I/O(IOCP),但 File.Copy 是原子操作,内部不暴露流,也不接受这个参数。强行用 FileStream 手动读写反而更慢。
性能影响真相:
- 机械硬盘上,顺序读+顺序写才是最快路径,
File.Copy内部已优化至此;自己用BufferedStream+ 小 buffer(如 4KB)只会增加系统调用次数 - SSD 上差异更小,瓶颈在内存拷贝和 FAT/NTFS 元数据更新,不是磁盘寻道
- 真正有效的提速点:用
FileOptions.WriteThrough关闭系统缓存(适合超大文件防 OOM),但会降低小文件性能,需按场景开关
复制前必须检查目标盘剩余空间和硬链接冲突
用户看到“复制完成”但实际只写入一半,大概率是目标盘爆满或遇到硬链接循环。这不是静默的问题,是静默掩盖了致命前提校验。
容易踩的坑:
- 用
DriveInfo.AvailableFreeSpace预估空间时,别直接用源目录DirectoryInfo.TotalSize(它不包含 NTFS 压缩、稀疏文件等真实占用,可能严重高估) - 检查硬链接:遍历源目录时对每个
FileInfo调用File.GetAttributes,若含FileAttributes.ReparsePoint且File.GetLinkTarget指向本目录内路径,必须报错退出,不能静默跳过 - 跨卷复制(如 C:\ → D:\)时,
File.Copy自动走“读-写”流程;同卷则尝试MoveFileEx的快速重命名,但静默复制逻辑里不应依赖这个行为,一律按读写处理更可控
静默不等于盲目执行。最常被忽略的是:没做空间预检就开干,结果卡在 99% 时磁盘写满,日志里只有一行 IOException: There is not enough space on the disk,而用户以为程序卡死。










