应优先通过 stat(Linux/macOS)或 GetFileInformationByHandle(Windows)比较 st_dev/st_ino 或卷序列号与文件索引号,而非依赖路径字符串归一化;若需路径比较,则 Windows 用 GetFinalPathNameByHandle,Linux/macOS 用 realpath。

Windows下用 GetFinalPathNameByHandle 解决路径归一化问题
Windows不保证路径字符串相等就代表同一文件,比如 C:ooar 和 ??C:ooar、\?C:ooar、甚至带相对路径的 C:oo..ooar 都可能指向同一个文件。直接字符串比较会漏判或误判。
正确做法是先打开路径对应句柄,再用 GetFinalPathNameByHandle 获取其规范化的 NT 路径(以 ?? 开头),然后比较结果字符串。注意:该函数要求路径可访问且调用者有读取权限,否则失败。
- 必须用
FILE_FLAG_BACKUP_SEMANTICS打开目录,否则GetFinalPathNameByHandle对目录返回错误 - 返回的路径含前缀
??,若需用户友好格式,可用FindFirstVolumeMountPoint或手动替换,但比较时保持原样即可 - 路径含重解析点(如符号链接、挂载点)时,该函数默认展开——这正是你想要的行为
Linux/macOS 用 realpath 处理符号链接和相对路径
realpath 是最直接的方案:它自动解析所有 ..、.、符号链接、硬链接,并返回绝对、规范、可访问的路径。只要两个路径最终能 stat 到同一个 st_dev + st_ino,realpath 就会给出相同字符串。
注意 realpath 的行为受参数影响:realpath(path, nullptr) 分配内存并返回指针,需 free;realpath(path, buf) 写入指定缓冲区,需确保足够大(PATH_MAX 安全)。
立即学习“C++免费学习笔记(深入)”;
- 如果路径不存在,
realpath返回nullptr,不能直接比较——先检查返回值是否非空 - 对 dangling symlink(悬空软链接),
realpath默认失败;加REALPATH_NO_CHECK(glibc 2.28+)可忽略存在性,但此时无法保证指向真实文件 - 跨文件系统硬链接虽共享
st_ino,但realpath仍会给出不同路径——这是正常现象,需配合stat双重验证
跨平台健壮判断:先 stat 再比对 st_dev 和 st_ino
字符串归一化(realpath / GetFinalPathNameByHandle)依赖路径可访问且无权限限制。真正底层、可靠的方式是调用 stat(POSIX)或 GetFileInformationByHandle(Windows),提取设备号与索引节点号,二者完全相同时即为同一文件/目录。
Windows 上需注意:st_ino 在 POSIX 层模拟不准确,应直接用 BY_HANDLE_FILE_INFORMATION 中的 nFileIndexLow/nFileIndexHigh 和 dwVolumeSerialNumber 组合判断。
- Linux/macOS:两次
stat成功后比较st_dev和st_ino即可,无需关心路径字符串 - Windows:必须用
CreateFile打开路径(带FILE_SHARE_READ),再调用GetFileInformationByHandle;对目录要加FILE_FLAG_BACKUP_SEMANTICS - 任一路径不可访问(权限不足、不存在、是断开的网络路径),则无法完成此判断——此时归一化方案也大概率失败
常见坑:相对路径、当前工作目录、UNC 路径处理不当
直接拼接或比较相对路径(如 ../config.json)而不先转绝对路径,必然出错。C++ 标准库无内置路径解析,std::filesystem::absolute 是 C++17 后的解法,但它在 Windows 上对 UNC 路径(\servershare)支持不稳定,某些旧版本会抛异常或返回错误格式。
更稳妥的做法是:Windows 下优先用 PathCchCanonicalize(推荐)或 GetFullPathName;Linux 下用 realpath 前先 chdir 到目标路径所在目录再解析(不推荐),或用 std::filesystem::weakly_canonical(C++17)作为 fallback。
-
std::filesystem::equivalent看似完美,但它内部仍依赖stat或平台 API,且在某些 Windows 版本上对长路径或符号链接处理有缺陷 - 网络路径(SMB/UNC)在 Windows 上需确认已映射或启用 WebClient 服务,否则
CreateFile会超时而非快速失败 - 容器或沙箱环境(如 Flatpak、WSL2)中,宿主机路径与容器内路径的
st_dev/st_ino可能不一致,此时必须依赖归一化路径而非 inode 比较


















