windows需通过ioctl_storage_query_property查physicaldrive的devicemediatype,linux读/sys/block/*/queue/rotational,macos无可靠api;三者均存在虚拟化、混合存储等导致结果不可靠的问题。

Windows下用IOCTL_STORAGE_QUERY_PROPERTY判断磁盘介质类型
Windows没有直接暴露“这个路径在SSD上吗”的API,得先从路径反查到物理磁盘,再查该磁盘的介质类型。核心是调用 DeviceIoControl 向磁盘句柄发送 IOCTL_STORAGE_QUERY_PROPERTY,并请求 StorageDeviceProperty,从中读取 DeviceMediaType 字段。
常见错误是直接对文件句柄调用——不行,必须打开对应物理卷的设备路径(如 \\.\C:),且需要管理员权限;否则会返回 ERROR_ACCESS_DENIED。
- 先用
GetVolumePathName把文件路径转成卷路径(如"D:\data\file.txt"→"D:\") - 再用
GetVolumeNameForVolumeMountPoint转成 NT 设备路径(如"\\?\Volume{...}\") - 提取卷GUID前缀,拼出物理磁盘路径:
\\.\PhysicalDriveX(需通过IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS关联) - 打开该
\\.\PhysicalDriveX句柄时,必须带FILE_SHARE_READ | FILE_SHARE_WRITE和GENERIC_READ,且进程需启用SE_MANAGE_VOLUME_NAME权限(通常需管理员)
Linux下通过/sys/block/*/queue/rotational判别
Linux不区分SSD/HDD,但内核用 /sys/block/*/queue/rotational 标识是否为旋转介质:值为 0 表示非旋转(大概率是SSD或NVMe),1 表示旋转(传统HDD)。这是最轻量、无需特权的方法。
关键难点在于:文件路径 → 块设备名。不能只靠 stat().st_dev,因为容器、overlayfs、btrfs subvolume 等场景下,st_dev 指向的是上层虚拟设备,而非底层物理盘。
- 用
stat获取文件所在挂载点(st_dev),再查/proc/mounts或findmnt -n -o SOURCE --target /path得到实际块设备路径(如/dev/sda2) - 从设备路径提取主设备名(如
sda2→sda),然后读取/sys/block/sda/queue/rotational - 注意符号链接:/dev/nvme0n1p1 的父设备是
nvme0n1,要逐级向上找直到device目录存在queue/rotational - 某些RAID或LVM逻辑卷可能返回
rotational=1即使后端是SSD——这是驱动/固件行为,无法绕过
macOS没有可靠用户态SSD检测机制
macOS不提供公开API或sysfs等接口供程序判断SSD。diskutil info 输出里的 Medium Type 字段(如 SSD)来自IOKit的 kIOPropertyMediumTypeKey,但该属性仅对Apple原装SSD稳定返回;第三方NVMe盘或USB-C SSD常返回 Generic 或空值。
实际开发中,若必须做粗略判断,可结合两项信号:
- 检查
IORegistryEntryCreateCFProperties中kIOPropertyMediumTypeKey是否等于CFSTR("SSD")—— 仅对部分设备有效 - 读取
IOBlockStorageDeviceCharacteristics中的kIOPropertyRotationRateKey:若值为0或不存在,倾向认为是非旋转介质 - 不要依赖
smartctl或ata命令:macOS默认禁用ATA passthrough,NVMe设备更无对应接口
跨平台判断的实际陷阱
所谓“SSD判断”本质是推测——操作系统和硬件抽象层(HAL)并不保证暴露真实物理特性。很多场景下结果不可靠:
- Windows Storage Spaces、Linux LVM cache、ZFS mirror 中的“SSD”只是逻辑角色,底层可能是HDD+SSD混合
- 某些PCIe SSD固件故意将
rotational设为1以兼容旧驱动,或设为0误导应用开启SSD优化 - 云平台(AWS EBS、Azure Disk)返回的永远是虚拟块设备,
rotational恒为0,但实际I/O延迟远高于本地NVMe - 容器内挂载的host路径,检测结果反映的是宿主机磁盘,而非容器运行环境感知的存储栈
真正影响性能的是随机IOPS和延迟,不是“是不是SSD”这个标签。如果目标是优化策略(比如跳过预读、调整buffer大小),建议直接测 randread latency 或用 ioctl(fd, BLKGETSIZE64) + clock_gettime 做微基准,比查介质类型更靠谱。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











