vss快照是windows卷级一致性只读副本,可绕过文件锁读取占用中文件;普通复制遇独占锁即失败。它非备份工具,需手动管理生命周期,且c#调用依赖com互操作或vsssharp库。

什么是 VSS 快照,它和普通文件复制有啥区别
VSS(Volume Shadow Copy Service)是 Windows 内置的卷级快照机制,能在文件被占用(如数据库、日志、打开的 Word 文档)时,生成一致性的只读副本。普通 File.Copy 或 Directory.GetFiles 在文件被独占锁住时会直接抛出 IOException 或 UnauthorizedAccessException,而 VSS 能绕过锁,拿到那一刻的磁盘块级一致性视图。
注意:VSS 不是“备份工具”,它不跨卷、不压缩、不加密,也不自动清理——快照生命周期需手动管理,否则会撑爆系统卷影存储空间。
C# 调用 VSS 的两种可行路径
.NET 没有原生 VSS API 封装,必须通过 COM 互操作调用 Windows 原生接口。主流做法只有两个:
- 使用微软官方提供的托管包装器
VSSSharp(已归档但可用,需 NuGet 安装Microsoft.VSSSharp) - 直接 P/Invoke 或 COM Interop 调用
IVssBackupComponents等接口(更底层,控制力强但易出错)
推荐初学者用 VSSSharp,它封装了初始化、添加卷、准备快照、获取路径等关键步骤。但要注意:该库仅支持 .NET Framework(net461 及以上),在 .NET Core / .NET 5+ 中需启用 COM 支持并手动注册类型库(vssadmin.exe 不可替代)。
创建快照的关键步骤与常见报错
使用 VSSSharp 创建一个 D: 卷快照的最小可行流程如下:
- 初始化
VssBackupComponents实例 - 调用
InitializeForBackup(必须以管理员权限运行,否则报E_ACCESSDENIED) - 调用
AddToSnapshotSet加入目标卷(如"D:\",注意结尾反斜杠) - 调用
PrepareForBackup和DoSnapshotSet - 从返回的
SnapshotSet中提取SnapshotDeviceObject(即快照挂载路径,形如\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy123)
常见卡点:
-
0x80042302 (VSS_E_OBJECT_NOT_FOUND):卷不支持 VSS(如 FAT32、网络驱动器、BitLocker 加密卷未解锁) -
0x8004231f (VSS_E_SNAPSHOT_SET_IN_PROGRESS):已有快照正在创建,需等待或清理残留 -
0x80042308 (VSS_E_MAXIMUM_NUMBER_OF_SNAPSHOTS_REACHED):默认单卷最多 64 个快照,用vssadmin list shadows查看,vssadmin delete shadows /for=D: /all清理
如何安全访问快照中的文件
快照路径(如 \?\GLOBALROOT\Device\HarddiskVolumeShadowCopy123)不能直接传给 File.ReadAllText,.NET 的 IO 类默认拒绝这类设备路径。必须:
- 使用
\?\前缀 + 完整设备路径构造FileStream(需指定FileOptions.None,禁用缓存) - 或将快照映射为临时驱动器号(不推荐,需调用
MountVol,权限复杂且易冲突) - 更稳妥的做法:用
Directory.EnumerateFiles配合\?\路径前缀遍历,再逐个用new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)打开
注意:FileInfo.Length 在快照路径下可能返回 0 或异常,应改用 FileStream.Length;所有快照句柄应在使用后立即释放,否则快照无法自动卸载,占用存储空间。
VSS 快照不是“复制即走”的轻量操作,它的生命周期、权限模型、路径兼容性都和常规文件操作完全不同。哪怕只是读取一个被锁定的 Excel 文件,也得先确认卷是否支持、是否有足够影子存储、是否以管理员身份启动进程——漏掉任意一环,DoSnapshotSet 就会静默失败或卡死。








