std::filesystem::equivalent 是判断两个路径是否指向同一物理文件的唯一可靠方式,它依赖系统api(windows用getfileinformationbyhandle,posix用stat),要求路径必须存在且可访问,否则抛出filesystem_error而非返回false。

std::filesystem::equivalent 是唯一靠谱的判断方式
直接用 std::filesystem::equivalent,别自己拼字符串、比路径名或检查 inode(Windows 没 inode)。它底层调用操作系统 API(GetFileInformationByHandle on Windows, stat + st_dev/st_ino on POSIX),真正判断「是不是同一个物理文件」。
常见错误是把 std::filesystem::equivalent 当成路径标准化工具——它不处理软链接跳转失败、权限不足等异常,也不自动 resolve symlink。如果传入的路径本身不可访问,函数会抛出 std::filesystem::filesystem_error,不是返回 false。
- 必须确保两个路径都存在且可访问,否则直接 throw
- 软链接会被跟随(即判断目标文件是否等价),但若软链接损坏或目标不可达,仍会报错
- 跨文件系统(比如 NTFS 和 FAT32 卷)也能正确判断,只要 OS 支持
路径必须先 exists() 再 equivalent(),否则容易 crash
很多人写成 equivalent(p1, p2) 一把梭,结果路径不存在就崩。C++ 标准规定:只要任一路径不存在、无权限、或根本无法 stat,equivalent 就抛异常,不会静默返回 false。
正确姿势是显式兜底:
try {
if (std::filesystem::exists(p1) && std::filesystem::exists(p2)) {
return std::filesystem::equivalent(p1, p2);
}
} catch (const std::filesystem::filesystem_error&) {
// 路径无效、权限不足、循环软链接等
return false;
}
-
exists()自身也可能抛异常(比如路径含非法字符),所以 try 块要包住它俩 - 不要用
status()替代exists()——status()在 dangling symlink 上可能返回file_status::symlink,但equivalent()还是会去 follow 它并失败 - Windows 上对长路径(>260 字符)、带
\?前缀的路径支持良好,但得确保传入的是宽字符串(std::wstring或 UTF-8 编码的std::string+ 启用 /utf-8 编译选项)
Linux/macOS 下注意挂载点和 bind mount 的行为
在 Linux 上,equivalent() 依赖 st_dev 和 st_ino。普通目录绑定挂载(bind mount)会让同一文件在不同挂载点下呈现不同 st_dev,导致 equivalent() 返回 false——即使它们指向完全相同的 inode。
这不是 bug,是设计如此:bind mount 创建了新的文件系统视图,OS 层面视为不同设备。
- 遇到 bind mount 场景,不能只信
equivalent(),需结合readlink("/proc/self/fd/...")或realpath()手动 normalize 路径再比对(但要注意符号链接循环) - overlayfs、btrfs subvolume 等也类似,
st_dev可能不一致 - macOS 的 APFS 快照、Case-insensitive 卷不影响判断,因为
st_dev/st_ino仍是唯一标识
替代方案只有 realpath + 字符串比较,但坑更多
有人绕开 equivalent(),改用 std::filesystem::canonical() 或 realpath() 把两个路径转成绝对路径再 strcmp。这在多数情况“看起来”有效,但实际更脆弱。
canonical() 会 resolve 所有 symlink 并检查每个组件是否存在;只要中间某级目录不存在,就抛异常。而 equivalent() 只关心最终目标是否同一实体,不验证路径中间态。
-
canonical()在 symlink 循环、权限中断、noexec 挂载点上极易失败 - Windows 上
canonical()对某些重解析点(如 junctions)行为不稳定,equivalent()更可靠 - 即使 canonical 成功,字符串相等 ≠ 物理等价:比如硬链接到同一文件的两个路径,canonical 后可能不同(取决于 link 创建时的相对路径)
真要手撸,至少用 std::filesystem::weakly_canonical() 配合 equivalent() 做 fallback,而不是替代。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











