linux下应先用statfs获取挂载点文件系统信息,再open挂载点内真实路径得到fd,最后ioctl(fd, blksszget)获取逻辑扇区大小;windows需createfile打开".c:"后调用deviceiocontrol+ioctl_disk_get_drive_geometry_ex读取bytespersector。

Linux 下用 statfs 和 ioctl 获取挂载点与逻辑块大小
直接读取挂载点信息不能只靠 getmntent,它不提供扇区大小;真正可靠的方式是先定位挂载路径(如 /home),再对任意该路径下的文件或目录调用 statfs 拿到文件系统类型和块大小,最后用 ioctl(fd, BLKSSZGET, &logical_sector) 获取底层逻辑扇区大小。
关键点:必须打开挂载点内某个真实存在的文件或目录(哪怕只读),才能拿到设备句柄去发 ioctl。常见错误是传入未挂载路径、符号链接目标路径,或忘记检查 errno ——比如 ENOTTY 表示 fd 不指向块设备,EBADF 说明文件没成功打开。
-
statfs("/home", &buf)中buf.f_bsize是文件系统推荐 I/O 块大小(非物理扇区) - 需额外用
open("/home", O_RDONLY | O_CLOEXEC)得到 fd,再ioctl(fd, BLKSSZGET, §or) - 注意:某些 overlayfs 或 tmpfs 挂载点无法获取物理扇区(
ioctl返回ENOTTY),此时应降级为使用f_bsize或报错提示
Windows 上用 GetDiskFreeSpaceEx 和 DeviceIoControl 读取卷信息
Windows 没有“挂载点”概念,但每个驱动器字母(如 C:)本质是 NTFS 卷的符号映射。要获取物理扇区大小,必须走设备控制接口:CreateFile 打开 \\.\C:,再发 IOCTL_DISK_GET_DRIVE_GEOMETRY_EX。
容易踩的坑:权限不足(需管理员提权)、路径格式错误(漏掉 \\.\ 前缀)、忽略 dwBytesReturned 检查导致结构体读取不全。另外 GetDiskFreeSpaceEx 只返回簇大小和剩余空间,不反映物理扇区。
-
GetDiskFreeSpaceEx(L"C:\", nullptr, &total, nullptr)→ 得到的是分配单元(簇)大小,不是扇区 - 正确流程:
h = CreateFile(L"\\.\C:", 0, FILE_SHARE_READ|FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr),再DeviceIoControl(h, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, ...) -
DiskGeometryEx.Geometry.BytesPerSector是逻辑扇区大小;BytesPerPhysicalSector是物理扇区(可能为 4096,尤其在 Advanced Format 硬盘上)
跨平台封装建议:避免硬编码路径解析逻辑
不要自己解析 /proc/mounts 或 WMI 输出字符串——格式易变且无标准分隔符。Linux 推荐用 setmntent("/proc/mounts", "r") + getmntent,Windows 推荐 FindFirstVolume + GetVolumePathNamesForVolumeName 组合,这才是稳定获取“某设备所有挂载路径”的方式。
一个典型误用:把 /dev/sda1 当作挂载点传给 statfs ——它不是挂载路径,statfs 会失败。必须传 /、/boot 这类实际被挂载的目录路径。
- Linux:遍历
/proc/mounts时过滤type字段(排除proc、sysfs等伪文件系统) - Windows:
GetVolumePathNamesForVolumeName返回多个挂载路径(如 C: 和 D:Data),需逐个处理 - 统一抽象层里,优先用挂载路径查设备,再查设备属性;而不是反向推导
物理扇区 vs 逻辑扇区:为什么 BLKSSZGET 和 IOCTL_DISK_GET_DRIVE_GEOMETRY_EX 都得调
现代 SSD 和 Advanced Format HDD 的物理扇区通常是 4096 字节,但操作系统和文件系统仍以 512 字节逻辑扇区对外呈现。若程序做底层 IO(如 raw disk read/write),必须区分二者:对齐到物理扇区才能获得最佳性能,否则触发 read-modify-write。
仅靠 statfs.f_bsize 或 GetDiskFreeSpaceEx 返回的“每扇区字节数”完全不可信——它们返回的是文件系统簇或逻辑扇区,不是硬件真实粒度。实测中,很多 NVMe 设备报告逻辑扇区 512,物理扇区 4096;而部分 SATA SSD 则两者均为 4096。
- Linux:
ioctl(fd, BLKSSZGET, &logical)和ioctl(fd, BLKPBSZGET, &physical)必须分别调用 - Windows:
DiskGeometryEx.Geometry.BytesPerSector是逻辑值,BytesPerPhysicalSector是物理值 - 若物理扇区 > 逻辑扇区,所有 direct IO 缓冲区地址和长度必须按物理扇区对齐(
posix_memalign+aligned_alloc)
最常被忽略的一点:即使你拿到了物理扇区大小,如果 open 时没加 O_DIRECT(Linux)或没用 FILE_FLAG_NO_BUFFERING(Windows),底层仍然会做缓冲和对齐转换,此时物理扇区信息就只是参考值。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











