File.Copy不自动创建目录且不处理元数据,需先Directory.CreateDirectory确保路径存在,显式传true覆盖文件;同卷用Move更高效原子,跨卷需判断根路径;大文件应分块异步复制并支持取消。

用 File.Copy 最直接,但目标目录不存在会炸
很多人写 File.Copy("a.txt", "D:\dest\b.txt"),结果抛出 DirectoryNotFoundException —— 因为 File.Copy 不自动创建父目录。它只管“复制文件”,不管“铺路”。
实操建议:
- 先用
Directory.CreateDirectory确保目标路径的父目录存在(这个方法是幂等的,重复调用没问题) - 再调用
File.Copy,并显式传true覆盖已有文件(否则目标存在时直接抛IOException) - 别依赖异常来判断目录是否存在——主动检查更稳、更可读
string source = "a.txt"; string dest = @"D:dest.txt"; Directory.CreateDirectory(Path.GetDirectoryName(dest)); File.Copy(source, dest, true);
File.Copy 和 File.Move 别混用场景
看起来都是“操作文件”,但语义和底层行为差很远:File.Copy 是读+写两步,File.Move 在同卷下是重命名(快、原子),跨卷才是拷贝+删源(慢、非原子)。误用会导致性能意外或逻辑漏洞。
常见错误现象:
- 想“迁移”文件却用了
Copy+ 手动Delete,结果中间出错,源文件丢了、目标又不全 - 在部署脚本里用
Move替代Copy,结果发现跨盘符失败,报IOException:“The process cannot access the file…”
使用场景判断口诀:要留原文件 → 用 Copy;要换位置且保证原子性(同盘)→ 用 Move;不确定是否同卷 → 先 Path.GetPathRoot 对比根路径,再分支处理。
大文件复制卡死?不是函数问题,是没加进度反馈和取消支持
File.Copy 是同步阻塞的,1GB 文件可能卡住 UI 线程十几秒,用户点×也无响应。这不是它“不行”,而是设计定位就是简单工具函数,不负责交互。
实操建议:
- UI 场景(WinForms/WPF)必须用
FileStream分块读写,配合IProgress<int>和CancellationToken - 别自己手写缓冲区大小——4KB 或 64KB 都行,但避免 1B 或 1GB 这种极端值(前者 syscall 太多,后者内存爆)
- 复制中途取消时,目标文件要主动
Delete并清理已写部分,否则残留半截文件
using var source = new FileStream(src, FileMode.Open, FileAccess.Read, FileShare.Read, 8192, FileOptions.Asynchronous); using var dest = new FileStream(dst, FileMode.Create, FileAccess.Write, FileShare.None, 8192, FileOptions.Asynchronous); await source.CopyToAsync(dest, 8192, cancellationToken);
权限、符号链接、只读属性这些细节,File.Copy 默认都不管
它只复制字节流,不继承 ACL、不解析软链接、不保留 ReadOnly 标志位。如果你需要“镜像式”拷贝(比如备份工具),这三处最容易漏掉。
关键差异点:
-
File.Copy复制后目标文件默认是“普通”属性,源文件带ReadOnly?目标没了 —— 得手动File.SetAttributes(dest, File.GetAttributes(src)) - 遇到 NTFS 符号链接(symlink),
File.Copy会把链接本身当普通文件复制过去(内容是路径字符串),而不是复制它指向的目标 —— 需用FileSystemInfo判断类型,再递归处理 - 跨用户复制时,ACL 权限不会自动继承。如果目标目录开了继承策略,新文件会获得默认继承权限;否则它只有创建者的基本权限 —— 别指望
File.Copy帮你做SetAccessControl
复杂点不在语法,而在你是否意识到:复制动作本身只是开始,元数据要不要、怎么要、由谁决定,得你自己划线。










