driveinfo.getdrives() 可快速获取已分配驱动器号的本地卷列表,但无法识别ntfs挂载点、未解锁bitlocker卷或脱机动态卷;需配合getvolumeinformation、getvolumepathnamesforvolumename等win32 api实现完整卷管理。

如何用 DriveInfo 获取本地卷列表(不依赖 WMI)
直接用 DriveInfo.GetDrives() 就能拿到当前系统所有挂载的卷,包括 C:、D:、网络映射盘(如果已连接)、甚至 USB 设备。它不查注册表也不调 WMI,纯 .NET BCL 实现,快且稳定。
但注意:它只返回「已分配驱动器号」的卷。NTFS 挂载点(比如 C:mntdata 这种无盘符的卷)、BitLocker 未解锁卷、或脱机状态的动态卷,DriveInfo 一律看不到。
- 必须在 Windows 上运行(.NET Core/.NET 5+ 在 Linux/macOS 返回空数组)
-
DriveInfo.IsReady一定要检查——光驱没放盘、U 盘被拔了一半时读TotalSize会抛IOException - 对 NTFS 挂载点,得换
ManagementObjectSearcher或GetVolumePathNamesForVolumeNameWin32 API
GetVolumeInformation 能拿到什么真实卷元数据
想确认一个卷是不是 NTFS、有没有压缩/加密、卷标是否含 Unicode、或者获取唯一卷序列号(用于识别重插后的 U 盘),就得调 Windows 原生 GetVolumeInformation。C# 里用 P/Invoke 调,别信某些 NuGet 包封装的“简化版”——它们常漏掉 lpVolumeSerialNumber 或把 lpMaximumComponentLength 当字符串处理。
- 传入路径必须是卷根目录(如
"C:\"),不能是子目录或文件 -
dwFileSystemFlags返回的标志位要 &FILE_VOLUME_IS_COMPRESSED这类常量,不是直接比数值 - 卷序列号是 uint32,但重启后可能变;真正稳定的标识是
Volume GUID Path(形如\\?\Volume{a1b2c3d4-...}\)
为什么 ManagementObjectSearcher 查 Win32_Volume 更全但更慢
它能列出所有卷,包括没盘符的、挂载点、隐藏卷、甚至 iSCSI 目标卷。因为底层走 WMI,数据来自 CIM Repository,不是实时扫描磁盘。
但代价明显:首次调用有几百毫秒延迟(WMI 服务冷启动),查询频率高时 CPU 占用突增,而且需要 System.Management NuGet 包(.NET Core 默认不带)。
- 过滤建议写成
"SELECT * FROM Win32_Volume WHERE DriveType=3"(3 是本地硬盘),避免拉回整个卷列表 -
Capacity和FreeSpace字段是 string 类型,得long.Parse(),不是直接当 int64 用 - 远程机器查询需 DCOM 权限,本地开发机默认关了,容易卡在
ManagementException
挂载点(Mount Point)和卷 GUID 的实际识别逻辑
一个物理磁盘可以分多个分区,每个分区可挂载到多个路径(比如 D: 和 C:data 指向同一卷)。这时候仅靠驱动器号会误判——你删了 C:data,DriveInfo 根本不知道 D: 还活着。
正确做法是:先用 GetVolumePathNamesForVolumeName 拿到某卷的所有挂载路径,再用 GetVolumeNameForVolumeMountPoint 反查路径归属哪个卷 GUID。二者配合才能建立「路径 ↔ 卷 ↔ 物理设备」映射。
- 卷 GUID 形如
\\?\Volume{...}\,末尾必须带反斜杠,否则 API 调用失败 -
GetVolumePathNamesForVolumeName返回的是 null 分隔的字符串数组,要用Split(' ')拆,别用String.Split默认行为 - 管理员权限不是必须的,但访问系统卷(如
System Volume Information)时仍可能被拒绝
卷管理真正的复杂点不在枚举,而在「状态同步」:U 盘热插拔后,DriveInfo 缓存不会自动更新,FileSystemWatcher 也监听不到盘符增减。得自己轮询或接 WM_DEVICECHANGE 消息——这点文档几乎从不提,但线上程序八成栽在这儿。









