getvolumeinformation可判断光盘只读性:需传入标准根路径(如"d:\"),检查file_read_only_volume标志及文件系统名(cdfs/udf),但需结合createfile写入测试或deviceiocontrol查询storagedeviceproperty以提高准确率。

用 GetVolumeInformation 检查光盘介质类型
Windows 下判断路径是否在只读光盘上,不能只看文件属性(GetFileAttributes 返回的 FILE_ATTRIBUTE_READONLY 对光盘无效),而要查卷的介质类型。核心是调用 GetVolumeInformation,传入路径所在卷的根目录(如 "D:\"),然后检查返回的 lpFileSystemFlags 和底层设备行为。
关键点:只读光盘(CD-ROM、DVD-ROM)通常报告 FILE_READ_ONLY_VOLUME 标志,且 lpFileSystemNameBuffer 常为 "CDFS" 或 "UDF"。但注意——该标志并非绝对可靠,部分虚拟光驱或刻录盘可能不设此旗,需结合其他线索。
- 先用
PathStripToRoot或手动截取路径根(如"E:\data\file.txt"→"E:\") - 确保路径末尾有双反斜杠(
"D:\"),否则GetVolumeInformation可能失败并返回错误码ERROR_INVALID_NAME - 若路径跨网络或为 UNC 路径(
"\\server\share"),该 API 不适用,会返回ERROR_NOT_SUPPORTED
用 DeviceIoControl 查询真实介质特性
更稳妥的方式是绕过文件系统层,直接向卷设备句柄发送 IOCTL_STORAGE_QUERY_PROPERTY,获取 StorageDeviceProperty 中的 RemovableMedia 和 ReadOnly 字段。这对物理光驱最准确,能区分“可擦写 DVD-RW”和“只读 DVD-ROM”。
操作步骤紧凑:
- 用
CreateFile打开卷设备,路径形如"\\.\D:"(注意双反斜杠加冒号,无反斜杠结尾) - 必须指定
GENERIC_READ权限和FILE_SHARE_READ | FILE_SHARE_WRITE - 构造
STORAGE_PROPERTY_QUERY,PropertyId = StorageDeviceProperty,QueryType = PropertyStandardQuery - 解析返回的
STORAGE_DEVICE_DESCRIPTOR:若ReadOnly为TRUE,且RemovableMedia为TRUE,基本可断定是只读光盘
缺点是需要管理员权限在某些系统上才能打开 \.X: 设备;普通用户进程可能收到 ERROR_ACCESS_DENIED。
为什么 GetFileAttributes 和 stat() 都不可靠
很多人第一反应是用 GetFileAttributes 查 FILE_ATTRIBUTE_READONLY,或 C++17 的 std::filesystem::status 看权限位——这两者在光盘上几乎总是返回“可写”,因为光盘的只读性是硬件/固件级的,不是文件系统标记的属性。
典型错误现象:
-
GetFileAttributes("D:\video.iso")返回0xFFFFFFFF(失败)或一个不含FILE_ATTRIBUTE_READONLY的值,让人误以为“可写” -
std::filesystem::status("D:\").permissions()返回owner_read | owner_write | ...,看似可写,但实际ofstream写入必然失败并抛std::filesystem::filesystem_error - 尝试创建文件时才暴露问题:
CreateFile返回ERROR_WRITE_PROTECTED,这才是最终判决依据
实际判断逻辑建议组合使用
没有单一对策能 100% 覆盖所有光驱、镜像工具和 Windows 版本。推荐分层验证:
- 第一步:用
GetVolumeInformation检查是否含FILE_READ_ONLY_VOLUME且文件系统为"CDFS"/"UDF" - 第二步:若第一步不确定(比如返回
"NTFS"但路径在虚拟光驱里),尝试以CREATE_ALWAYS打开一个临时文件,捕获ERROR_WRITE_PROTECTED或ERROR_ACCESS_DENIED - 第三步(高可靠性需求):仅对本地物理驱动器走
DeviceIoControl路径,跳过网络、RAMDisk、WSL2 挂载点等异常情况
真正容易被忽略的是路径归一化——用户传入 "d:/folder"、"D:/"、"\\?\D:\ 时,GetVolumeInformation 对大小写和前缀敏感,必须标准化为 "D:\" 格式再调用,否则可能查错卷。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











