.net 的 system.io 不支持 cow,windows 上唯一官方支持的 cow 快照机制是 vss(需管理员权限和 com 调用),refs 块克隆需手动调用 deviceiocontrol,二者均无托管封装。

Windows 上 C# 没有原生 CoW 文件系统 API
直接说结论:.NET 的 System.IO 层面完全不暴露 NTFS 或 ReFS 的写时复制(CoW)能力,也没有跨平台的 CoW 抽象。所谓“C# 利用 CoW 实现快照”,本质是调用 Windows 底层卷影复制服务(VSS)或依赖文件系统特性手动模拟,不是语言或运行时内置功能。
常见错误现象:File.Copy() 即使目标在同一个 NTFS 卷上,也仍是完整字节拷贝;Directory.Move() 跨卷失败但同卷也不触发 CoW —— 它只是重命名,和 CoW 无关。
- VSS 是唯一被 Windows 官方支持的、能产生真正 CoW 快照的机制,但它是 COM 接口,需 P/Invoke 或第三方封装(如
AlphaVSS) - ReFS 支持稀疏文件和块克隆(
FSCTL_DUPLICATE_EXTENTS_TO_FILE),但 .NET 没有对应托管封装,必须用DeviceIoControl调用 - 别指望
FileStream构造函数加个 flag 就开启 CoW —— 这种设计根本不存在
用 AlphaVSS 做 VSS 快照的最小可行路径
VSS 是目前最可靠、兼容性最好的方案,但它不是“文件级快照”,而是“卷级快照”:你拿到的是一个只读的卷映射点(如 \?GLOBALROOTDeviceHarddiskVolumeShadowCopy123),再从那里读取文件。
使用场景:备份工具、数据库一致性快照、防误删临时副本。
- 必须以管理员权限运行,否则
CreateSnapshot直接抛E_ACCESSDENIED - 快照生命周期要手动管理:
StartSnapshotSet→AddToSnapshotSet→DoSnapshotSet→ 后续用完得DeleteSnapshots - 快照路径不能直接传给
File.ReadAllText:需拼成\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopyXX\path\to\file.txt格式 - 示例关键调用:
vssBackupComponents.StartSnapshotSet()、vssBackupComponents.AddToSnapshotSet("C:\")、vssBackupComponents.DoSnapshotSet()
ReFS 块克隆(Block Cloning)的 C# 调用要点
如果你明确控制环境(Windows Server 2016+ + ReFS 卷),且只需“快速复制大文件的逻辑副本”,FSCTL_DUPLICATE_EXTENTS_TO_FILE 是更轻量的选择 —— 它在内核态做块指针复制,毫秒级完成,且副本可写(真 CoW 行为)。
性能影响:对 10GB 文件,克隆耗时通常
- 必须确保源文件和目标文件在同一 ReFS 卷、且都启用稀疏文件属性(
File.SetAttributes(path, FileAttributes.SparseFile)) - 需用
DeviceIoControl+DUPLICATE_EXTENTS_DATA结构体,不能用FileStream高级 API - 目标文件必须已存在且大小 ≥ 源文件(可用
SetLength预分配),否则调用返回ERROR_INVALID_PARAMETER - 错误信息典型值:
ERROR_NOT_SUPPORTED(非 ReFS 卷)、ERROR_INVALID_FUNCTION(文件不在同一卷)
别踩的坑:CoW ≠ 硬链接,也 ≠ 内存映射
硬链接(CreateHardLink)只是多一个目录项指向同一 MFT 记录,删光所有链接才释放空间;内存映射(MemoryMappedFile)是虚拟地址映射,不涉及磁盘块共享。这两者都不提供 CoW 的“修改时自动分离”语义。
容易混淆的点:
-
File.CreateSymbolicLink是符号链接,和 CoW 完全无关 - 试图用
FileStream的FileOptions.WriteThrough或NoBuffering影响 CoW?无效 —— 这些只控制缓存行为 - Wine 或 Linux Mono 下想用 btrfs CoW?.NET 6+ 的
File.Copy在 btrfs 上仍走常规 copy,不调用BTRFS_IOC_CLONE_RANGE
真正需要 CoW 语义时,要么接受 VSS 的卷粒度和权限代价,要么自己用 P/Invoke 打通 ReFS 块克隆 —— 中间没有“简单开关”。








