用 stat() 获取 inode 号最直接:调用 stat() 传路径获取 struct stat 中的 st_ino 字段,注意检查返回值、避免空指针、正确处理 std::string::c_str() 生命周期,并用 %lu 或 to_string 打印 st_ino。

用 stat() 获取 inode 号是最直接的方式
Linux 下每个文件在 ext4/xfs 等文件系统中都有唯一 st_ino,它就是 inode 号。C++ 没有原生文件元数据 API,必须调用 POSIX stat() 系统调用封装函数。
关键点:不能用 fstat() 除非你已打开文件描述符;对路径操作优先用 stat();lstat() 用于区分符号链接本身和目标。
常见错误是传入空指针或未检查返回值:stat() 失败时返回 -1,errno 才有效——比如 ENOENT(路径不存在)、EACCES(无权限读目录)。
-
struct stat sb;必须先定义再传地址,别传&sb写成sb - 路径字符串需以 null 结尾,避免
std::string::c_str()临时对象生命周期问题(建议用const char* path = filepath.c_str();显式绑定) -
sb.st_ino是ino_t类型,打印时用%lu或std::to_string(sb.st_ino),别直接std::cout (可能截断)
卷元数据(filesystem ID)得靠 statfs() 或 statvfs()
stat() 只给单个文件的 inode 和设备号(st_dev),但“卷”信息——比如文件系统类型、总空间、挂载点所属设备——需要另一组系统调用。statfs() 更底层(返回 fsid_t、f_type),statvfs() 更可移植(POSIX 标准,返回 unsigned long 的 f_fsid)。
立即学习“C++免费学习笔记(深入)”;
根据 package.json 中的 engines 字段自动检测 Node.js 版本需求,未安装 nvm 时自动安装并切换至对应版本。支持 Windows、macOS、Linux。适用于 Node.js 项目开发、版本切换和环境配置。
注意:st_dev 是设备号(如 0x801 表示 sda1),但它不等于卷唯一 ID;多个挂载点可能共享同一 st_dev(例如 bind mount),而 f_fsid 在同一内核实例中对每个挂载点是唯一的。
- 用
statvfs()时,传入**路径名**(非文件,是挂载点路径,如"/home"),不是文件路径本身 -
f_fsid是实现定义的,glibc 中常为uint64_t,但标准只保证它是unsigned long;打印建议用printf("%#lx", vfs.f_fsid) - 若需判断是否同一文件系统,比较
st_dev通常够用;若需跨主机/持久化标识,应结合statfs.f_fsid+statfs.f_type(如0xef53是 ext4)
获取真实设备路径要解析 st_dev 主次设备号
st_dev 是一个 dev_t,高 12 位是主设备号(major),低 20 位是次设备号(minor)。它指向的是内核中的块设备,不是 /dev/sda1 这种路径名。
要反查设备路径,得读 /proc/self/mounts 或调用 udevadm info --export-db,但 C++ 里更实际的做法是:用 major(st_dev) 和 minor(st_dev) 宏提取数值,再匹配 /sys/dev/block/*/uevent 中的 MAJOR=/MINOR= 字段(需 root 权限或读取权限)。
- 别手动位运算解
dev_t:用#include <sys></sys>后的major()/minor()函数 - 普通用户无法访问所有
/sys节点,st_dev值本身可用于stat()对比(同设备即同卷),但还原设备名属于运维层逻辑,不应嵌入核心业务代码 - 容器环境(如 Docker)中
st_dev可能被 namespace 隔离,statfs.f_fsid更可靠
性能与线程安全注意事项
stat() 和 statvfs() 都是系统调用,会陷入内核;频繁调用(如遍历目录)会显著拖慢程序。而且它们不是异步安全的——在信号处理函数中调用会导致未定义行为。
- 批量操作时,优先用
scandir()+dirfd+fstatat(),避免重复路径解析 -
stat()不是线程安全的?错——它本身是线程安全的;但全局errno是线程局部的,所以多线程中仍需检查返回值而非依赖 errno 是否变化 - 某些旧版 glibc 在 NFS 挂载点上
stat()可能阻塞数秒,生产环境建议加超时(用signalfd+alarm()不推荐;更稳妥是 fork 子进程或用libuv异步 stat)
inode 和卷元数据看似简单,但混用 stat/statfs/fstatat、忽略设备号语义、在容器里硬编码 /dev 路径,是线上排查存储类 bug 最常卡住的地方。

















