商城首页欢迎来到中国正版软件门户

您的位置:首页 >c++如何获取Windows下任意文件的唯一文件标识符【技巧】

c++如何获取Windows下任意文件的唯一文件标识符【技巧】

  发布于2026-05-03 阅读(0)

扫一扫,手机访问

C++如何获取Windows下任意文件的唯一文件标识符【技巧】

Windows下稳定标识文件的是FILE_ID,由VolumeSerialNumber与FileId组合构成;需用GetFileInformationByHandleEx(FileIdInfo)获取,句柄须以FILE_READ_ATTRIBUTES权限加FILE_FLAG_BACKUP_SEMANTICS打开。

c++如何获取Windows下任意文件的唯一文件标识符【技巧】

什么是Windows文件的唯一标识符

在Windows系统里,想稳定地追踪一个文件,光靠文件名和路径可不够。文件重命名了怎么办?移动到同个磁盘的其他文件夹里呢?这时候,真正能扛得住这些变化的,是内核层面的FILE_ID

这个标识符由两部分“拼”起来:dwVolumeSerialNumber(卷序列号)和FileId(一个ULARGE_INTEGER)。这里有个常见的误区:很多人习惯用GetFileInformationByHandle返回的nFileIndexHighnFileIndexLow。其实,这只是旧式FAT/NTFS的文件索引,一旦遇到ReFS文件系统或者某些符号链接场景,它就可能“掉链子”。真正现代且可靠的做法,是使用GetFileInformationByHandleEx配合FileIdInfo这个信息类。

GetFileInformationByHandleEx获取FILE_ID

具体怎么操作?关键在于两步:拿到正确的句柄,然后请求正确的信息。

首先,句柄的打开方式有讲究。权限只需要FILE_READ_ATTRIBUTES,完全不需要GENERIC_READ(这意味着你甚至不用有读取文件内容的权限)。但一个高频错误是,忘了加上FILE_FLAG_BACKUP_SEMANTICS这个标志位。对于目录,不加它肯定失败;对于普通文件,加上它能有效绕过一些访问控制列表(ACL)的拦截,算是“最佳实践”。

流程可以拆解为以下几步:

  • 调用CreateFile,将dwDesiredAccess参数设为FILE_READ_ATTRIBUTES,并在dwFlagsAndAttributes中包含FILE_FLAG_BACKUP_SEMANTICS
  • 仔细检查返回的句柄是否为INVALID_HANDLE_VALUE,确认有效后,再调用GetFileInformationByHandleEx
  • 调用时,第三个参数传FileIdInfo,系统会将信息填充到FILE_ID_INFO结构体中。记住,只有VolumeSerialNumberFileId组合在一起,才是那个跨系统重启都稳定的唯一ID。
HANDLE h = CreateFile(L"C:\test.txt", FILE_READ_ATTRIBUTES,
                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                      nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (h != INVALID_HANDLE_VALUE) {
    FILE_ID_INFO info = {};
    if (GetFileInformationByHandleEx(h, FileIdInfo, &info, sizeof(info))) {
        // info.VolumeSerialNumber + info.FileId 为唯一标识
    }
    CloseHandle(h);
}

为什么不用GetFileInformationByHandlenFileIndex

你可能会问,旧API不是也能拿到一个索引号吗?为什么非要换新的?

根本原因在于“稳定性”和“普适性”。GetFileInformationByHandle返回的nFileIndex,在NTFS上确实对应文件的MFT(主文件表)索引号。但问题在于,它不保证持久不变——比如系统经过一次磁盘碎片整理,这个索引就可能发生变化。更关键的是,在ReFS这类现代文件系统上,它基本就“失灵”了,nFileIndexHigh会恒为0。

反观FileIdInfo提供的信息,是由文件系统驱动本身保证的全局唯一且持久的标识。只要文件没被物理删除,这个ID就不会变。当然,新技术有门槛:

  • 旧API的nFileIndex在Windows Server 2012 R2及更高版本的ReFS卷上已无意义。
  • 即使在NTFS上,如果启用了极少使用的“对象ID”功能,nFileIndex也可能被绕过。
  • FileIdInfo要求的最低系统版本是Windows 8或Server 2012,这意味着它无法在XP或Windows 7上使用。

实际使用时要注意路径和权限边界

掌握了核心API,在实际编码中还得留心几个“边界情况”,否则很容易踩坑。

首先是路径解析问题。遇到符号链接、挂载点或重解析点,CreateFile的默认行为是“解引用”,即拿到目标文件的ID。如果你想要的是链接文件本身的ID,就需要在打开时额外加上FILE_FLAG_OPEN_REPARSE_POINT标志。

其次是网络路径。访问UNC路径时,必须确保网络驱动器已映射,或者SMB签名已启用。否则,尝试获取FILE_ID很可能失败,返回空值或ERROR_NOT_SUPPORTED错误。

立即学习“C++免费学习笔记(深入)”;

  • 访问远程文件时,如果FileIdInfo返回ERROR_NOT_SUPPORTEDGetFileInformationByHandle并结合ftLastWriteTime等属性进行辅助校验。
  • 操作目录时,FILE_FLAG_BACKUP_SEMANTICS标志是必需的,缺少它会导致CreateFile直接失败。
  • 在UWP沙盒环境或使用受限令牌的进程中,可能无法成功获取FileIdInfo,此时应检查GetLastError()是否为ERROR_ACCESS_DENIED

最后,必须明确FILE_ID的本质:它既不是基于文件内容计算出的哈希值,也不依赖文件路径。它是文件系统分配的内部元数据ID。只要文件没被删除、没有跨卷移动,这个ID就是唯一的。但千万别把它当作加密或安全凭证来用——因为它可以被枚举,本身也不具备防篡改特性。

本文转载于:https://www.php.cn/faq/2313872.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注