GetVolumeInformation是Windows下检查卷只读状态最可靠方式,通过dwFileSystemFlags中FILE_READ_ONLY_VOLUME标志判断;路径须为"X:"格式,失败时需用CreateFile尝试打开写句柄兜底。

用 GetVolumeInformation 检查卷的文件系统特性
Windows 下最可靠的方式不是检查路径本身,而是获取其所在卷的属性。只读媒体(如光盘)通常在卷级别暴露为只读,GetVolumeInformation 返回的 dwFileSystemFlags 中若包含 FILE_READ_ONLY_VOLUME,就表示整个卷是只读的——这比尝试写文件再捕获错误更直接、更安全。
注意:该标志仅对 NTFS/FAT 等支持挂载时标记只读的文件系统有效;对 UDF(光盘常用)也适用,但需确保驱动正确上报。某些老旧光驱或虚拟光驱可能不设此标志,这时需 fallback 到写测试。
- 传入路径只需是任意一个有效子路径(如
"D:\test"或"D:\"),函数会自动解析到根卷 -
lpRootPathName必须以"X:\"格式结尾(双反斜杠),不能是"X:"或"X:\dir" - 返回值为 0 表示失败,需调用
GetLastError()判断原因(如路径不存在、无访问权限)
fallback:用 CreateFile 尝试以写方式打开根目录
当 GetVolumeInformation 未返回 FILE_READ_ONLY_VOLUME,但你仍怀疑是只读光盘(比如用户插入了 CD-ROM 后报告“无法保存”),可以尝试以 GENERIC_WRITE 打开根目录句柄。光盘设备即使不支持写入,也会在打开阶段拒绝写权限请求,比创建临时文件更轻量、更少副作用。
关键点在于:不要写内容,只测试能否获得写句柄;且必须指定 FILE_FLAG_NO_BUFFERING | FILE_FLAG_OPEN_REPARSE_POINT 避免被重定向或缓存干扰。
- 路径格式同上,必须是
"D:\"形式 - 若
CreateFile返回INVALID_HANDLE_VALUE且GetLastError()为ERROR_ACCESS_DENIED或ERROR_WRITE_PROTECT,基本可判定为只读媒体 - 务必调用
CloseHandle,哪怕打开失败(某些驱动在失败时仍可能返回半初始化句柄)
Linux/macOS 下用 statfs 查看 f_flags 中的 ST_RDONLY
POSIX 系统没有“卷”概念,但每个挂载点有独立挂载标志。statfs()(或更现代的 statvfs())能获取挂载选项,其中 ST_RDONLY 置位即表示只读挂载——光盘、只读 NFS、mount -o ro 的 ext4 分区都符合。
注意:statfs 对路径的要求比 Windows 更宽松,传入任意子路径(如 "/mnt/cdrom/file.txt")即可,它会自动定位到所属文件系统根。
- 使用
statvfs()更便携,但需检查f_flag & ST_RDONLY,而非直接比较f_flag == ST_RDONLY - 某些只读 FUSE 文件系统(如
archivemount)可能不正确设置该标志,此时只能靠写测试兜底 - 如果
statvfs失败(errno == ENOENT),说明路径不存在或跨了多个挂载点,需先用realpath()解析并stat()确认是否为目录
别忽略“伪只读”场景:权限不足 ≠ 媒体只读
用户常把 ERROR_ACCESS_DENIED 或 EACCES 直接当成只读媒体,其实更大概率是当前进程没权限(UAC 提权缺失、SELinux 限制、NTFS ACL 拒绝)。真正的只读媒体特征是:所有写操作(包括 CreateFile、open(O_WRONLY)、fchmod)在**打开/创建阶段就失败**,且错误码明确指向介质保护(ERROR_WRITE_PROTECT / EROFS),而不是权限或路径问题。
实际判断逻辑应分层:先查卷/挂载标志 → 再试开写句柄 → 最后才考虑写文件测试。跳过前两步直接创建临时文件,不仅慢,还可能因磁盘满、防病毒拦截等误判。
真正容易被忽略的是:某些光驱固件在未加载光盘时也返回只读标志,或者 USB 光驱在热插拔后状态未同步。这时候需要结合 GetDriveType(Windows)或 /proc/mounts(Linux)确认设备类型和实时挂载状态。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











