copytoasync仅适用于本地或局域网内已稳定挂载、低延迟的路径;用于远端smb或云盘易超时失败或静默截断,不解决跨地域、高延迟、断连重试等灾备问题。

用 CopyToAsync 做本地或局域网内文件异步复制
它能避免阻塞主线程,但不解决跨地域、高延迟、断连重试等灾备问题。常见误用是直接拿它去复制到远端 SMB 共享或挂载的云盘路径,结果超时失败或 silently 截断。
实操建议:
-
CopyToAsync只适合已稳定挂载、低延迟( - 务必包裹
try/catch捕获IOException和OperationCanceledException,网络抖动时容易抛出后者 - 不要依赖默认缓冲区大小(8KB),跨网络场景下建议显式传入
bufferSize: 64 * 1024或更大,减少 syscall 次数 - 示例:
using var source = File.OpenRead(@"C:dataackup.zip"); using var dest = File.Create(@"\nasackupsackup.zip"); await source.CopyToAsync(dest, 64 * 1024, cancellationToken);
跨地域灾备必须自己实现分块 + 断点续传 + 校验
没有现成 .NET API 能直接“异步灾备”。云厂商 SDK(如 Azure.Storage.Blobs)或 S3 客户端(AwsSdk)只管上传/下载,不自动处理路径映射、目录结构同步、失败后跳过已传块等逻辑。
实操建议:
- 把大文件切为
4MB左右的块(适配多数对象存储分段上传最小尺寸),每块独立上传并记录ETag或MD5 - 维护一个轻量元数据文件(JSON),存每个文件的
lastModified、size、blockHashes,上传前比对避免全量重传 - 使用
HttpClient+PutObjectAsync(S3)或UploadAsync(Blob)替代FileStream直传,才能真正走 HTTP 协议栈,支持重试和代理 - 别信
File.Copy的overwrite参数——跨地域时目标不存在、权限不足、磁盘满,错误码完全不同,得靠状态码和响应体判断
FileSystemWatcher 不能用于灾备触发
它在跨网络共享路径(如
egion-bshare)上基本失效:连接中断后不会自动重连,事件丢失率高,且无法区分“新建文件”和“写入未完成的临时文件”。
实操建议:
- 灾备触发必须基于可靠信号源:数据库变更日志、消息队列(如
RabbitMQ中的file_ready事件)、或定时扫描(配合FindFirstFileEx+FILE_ATTRIBUTE_ARCHIVE标记) - 如果非要用监听,只限本地卷,且必须加
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName,并忽略以.tmp、~$开头的文件名 - 每次收到事件后,先
Thread.Sleep(100)再检查文件是否可读、长度是否稳定——防编辑器双写、杀毒软件锁文件
异步不是并发,别盲目开 Task.WhenAll
同时启动 50 个 UploadAsync 任务,大概率触发远程服务限流(如 S3 的 400 TooManyRequests),或耗尽本地 socket 连接池,反而拖慢整体进度。
实操建议:
- 用
SemaphoreSlim控制并发数,云对象存储建议设为4–8,专线直连 IDC 存储可放宽到16 - 按文件大小分级调度:小文件(
- 记录每个任务的
ElapsedMilliseconds,动态调整后续任务的超时时间(如平均 2s/MB,则 100MB 文件设Timeout = 220s)
真正的跨地域异步灾备,核心不在“异步”而在“状态可追溯、失败可定位、重试有边界”。很多人卡在以为上传成功=灾备完成,其实校验失败、时钟不同步导致的 LastModified 错误、甚至对象存储的 eventual consistency 都会让一致性检查静默失败。









