Go语言无法跨平台直接读取磁盘分区表,必须按系统分路径处理:Linux/macOS用ioctl或sysfs+原始设备读取,Windows需WMI或DeviceIoControl,且均需管理员/root权限。

Go 语言无法跨平台直接读取磁盘分区表(如 MBR/GPT)结构,必须按操作系统分路径处理;Linux/macOS 需用 unix.Ioctl 或 ioctl 系统调用配合原始设备文件,Windows 必须走 WMI 或 windows.DeviceIoControl,且多数场景需管理员/root 权限。
Linux 下用 unix.Ioctl 读取 GPT/MBR 分区布局
Linux 内核不提供标准 sysfs 或 proc 接口暴露原始分区表字节,gopsutil/disk 也不覆盖该层。真实做法是打开块设备(如 /dev/sda),用 unix.Ioctl 调用 BLKPG 或 HDIO_GETGEO,但更通用的是读取 /sys/block/*/slaves 和 /sys/block/*/ext_range 辅助定位,再用 os.Open + io.ReadFull 读前 512 字节(MBR)或 LBA1(GPT header)。
- 必须以
O_RDONLY打开设备文件,普通用户默认无权限,容器中常被seccomp拦截 - GPT 头在 LBA1(512 字节偏移),但需先确认设备是否为 GPT:检查 LBA0 的 protective MBR 中
0xEE分区类型 - 读取后要手动解析二进制结构:
PartitionStyle、StartingLBA、PartitionSize等字段都是小端序,不能靠binary.Read直接映射 - 别用
fdisk -l /dev/sda封装——命令可能不存在、输出格式随版本变动、解析易错
Windows 下必须用 WMI 或 DeviceIoControl 获取分区 GUID 和偏移
Windows 不暴露裸设备字节流给用户态程序,diskpart 或 Get-Partition 的数据最终来自 WMI Win32_DiskPartition 或底层 IOCTL_DISK_GET_DRIVE_LAYOUT_EX。Go 中只能选其一:
- WMI 方案依赖
github.com/StackExchange/wmi,查询SELECT * FROM Win32_DiskPartition可得DeviceID(如\.PHYSICALDRIVE0)、StartingOffset、Size、PrimaryPartition,但拿不到 GPTPartitionIdGUID - 要 GUID 必须用
windows.DeviceIoControl调用IOCTL_DISK_GET_DRIVE_LAYOUT_EX,传入*DRIVE_LAYOUT_INFORMATION_EX结构体指针,再逐个解析PartitionInfo数组里的PARTITION_INFORMATION_GPT - 所有 DeviceIoControl 调用必须以管理员权限运行,否则返回
ERROR_ACCESS_DENIED - WMI 查询慢(毫秒级)、可能被禁用;DeviceIoControl 快但需手写大量 unsafe 指针和结构体对齐
gopsutil/disk.Partitions() 返回的不是分区表,只是挂载信息
很多人误以为 disk.Partitions(true) 能拿到分区起始扇区、类型、GUID,其实它只封装了 /proc/mounts 或 GetDriveType,字段如 Device(/dev/sda1)、Mountpoint(/)、Fstype(ext4)全是运行时挂载态数据,和底层分区表无关。
立即学习“go语言免费学习笔记(深入)”;
-
Device字符串不保证是真实块设备路径(可能是 LVM 逻辑卷、mdadm RAID、zvol) - 同一个物理磁盘多个分区,
Partitions()返回多条记录,但彼此无拓扑关系(谁在谁前面、是否连续) - 想从挂载点反推分区位置?只能靠
/sys/block/sda/sda1/start这类 sysfs 文件,但仅限 Linux,且需 root - 别试图用
filepath.Base(p.Device)提取分区号来推断顺序——/dev/nvme0n1p1和/dev/sda1编号规则完全不同
跨平台统一获取分区信息目前没有可靠方案
真正跨平台(Linux/macOS/Windows)的 Go 库不存在。macOS 用 diskutil list -plist 解析 XML,Linux 用 lsblk -J 或 ioctl,Windows 用 WMI,三者返回字段、精度、权限要求全不同。硬要统一,只能:
- 按
//go:build linux、//go:build windows拆分实现,各自调用原生接口 - 接受“只支持有 root/admin 权限的环境”,否则直接报错退出
- 放弃原始扇区偏移、GUID、分区样式等底层字段,只取
Device+Mountpoint+Fstype这类高层抽象(即gopsutil/disk能提供的全部) - 若目标是识别磁盘唯一性,优先用文件系统 UUID(通过
/dev/disk/by-uuid/反查),而非分区表 GUID —— 前者稳定、可挂载、无需权限
分区表是操作系统内核直接管理的底层结构,Go 运行时不会、也不能绕过权限模型去触碰它。任何看似“简单”的封装,背后都藏着权限、兼容性、解析鲁棒性的坑。真要动手,先确认你到底需要什么:是展示磁盘拓扑(可用 lsblk),还是做分区校验(必须 ioctl),或是绑定设备到业务逻辑(用 UUID 更稳)。


















