最直接方式是调用stat()填充struct stat后读取sb.st_ino,但必须检查返回值是否为0且配合st_dev才能唯一标识文件,因st_ino仅在同设备内唯一。

用 stat() 获取文件 inode 号最直接
Linux/macOS 下,C++ 本身不提供跨平台 inode 接口,必须调用 POSIX 系统调用。最常用的是 stat(),它把文件元数据填进 struct stat,其中 st_ino 字段就是 inode 号。
注意:不能用 fstat() 替代(除非你已有打开的 fd),因为 fstat() 不接受路径字符串;也不能用 lstat() 除非你明确想绕过符号链接——它返回的是链接文件自身的 inode,不是目标文件的。
示例片段:
#include <sys>
#include <iostream>
struct stat sb;
if (stat("/path/to/file", &sb) == 0) {
std::cout
<p>常见错误:<code>stat()</code> 对相对路径按当前工作目录解析,若路径不存在、权限不足或遇到挂载点边界(如 NFS、/proc),会返回 -1 并设 <code>errno</code> 为 <code>ENOENT</code>、<code>EACCES</code> 或 <code>ENOTDIR</code> 等。</p>
<h3>为什么 <code>st_ino</code> 在不同挂载点上可能重复</h3>
<p>inode 号是文件系统级别的标识符,不是全局唯一的。同一台机器上,<code>/dev/sda1</code> 和 <code>/dev/sdb1</code> 各自维护独立的 inode 编号空间,所以两个不同分区上的文件完全可能有相同的 <code>st_ino</code> 值。</p>
<p>这意味着仅靠 <code>st_ino</code> 无法唯一标识一个文件——你还得结合 <code>st_dev</code>(设备号)一起判断。POSIX 规定“同一设备上的相同 inode 号代表同一文件”,反过来说,<code>(st_dev, st_ino)</code> 才构成主机内相对稳定的文件身份对。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master"><img
src="https://img.php.cn/upload/skill/000/000/081/179051228971575.jpg" alt="C++ Code Review Master" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master" class="overflowclass">C++ Code Review Master</a>
<p class="overflowclass">组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。</p>
</div>
<a rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<p>实际使用中容易忽略这点,比如用 inode 做缓存 key 却没带上 <code>st_dev</code>,结果在多磁盘环境里发生误命中。</p>
<h3>glibc 的 <code>stat()</code> 调用链其实很短</h3>
<p>glibc 的 <code>stat()</code> 几乎就是对内核 <code>sys_statx</code>(较新)或 <code>sys_stat</code>(传统)的封装,中间几乎没有额外逻辑。你可以用 <code>strace -e trace=stat,statx</code> 验证:</p>
<pre class="brush:php;toolbar:false;">$ strace -e trace=stat,statx ./a.out 2>&1 | grep stat
stat("/etc/passwd", {st_mode=S_IFREG|0644, st_size=2795, ..., st_ino=123456, ...}) = 0
关键事实:
-
stat()是轻量级系统调用,不涉及页缓存读取,只查 inode 表和 dentry 缓存 - 在 ext4 上,只要 dentry 未过期,
stat()基本是 O(1);若需回溯路径(比如多层 ../),耗时会随路径深度上升 - 某些文件系统(如 overlayfs、procfs)返回的
st_ino是合成值,并非真实磁盘 inode,不可用于底层存储定位
Windows 上没有等价的 inode 概念,别硬套
Windows NTFS 使用 file ID(通过 GetFileInformationByHandle() 获取 dwVolumeSerialNumber + nFileIndexHigh/Low),但它的语义和生命周期与 Unix inode 不同:重命名不改变 file ID,但硬链接行为、卷快照、重定向 I/O 都会影响其稳定性。
如果你写跨平台代码,不要试图抽象出“统一 inode 类型”。更现实的做法是:
- Linux/macOS:用
(st_dev, st_ino) - Windows:用
GetFileInformationByHandle()的FILE_ID_INFO(需 Win10 1607+)或退化为完整路径哈希 - 任何平台都避免假设 inode 永久不变——硬链接增加、文件被 mv 到另一文件系统、备份还原后,inode 都可能变
真正难的从来不是怎么取到 st_ino,而是搞清它在哪种上下文里才具备你想要的“唯一性”和“稳定性”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










