如何将目录路径转换为唯一的数字标识符 (Linux/C++)

How do I convert a directory path to a unique numerical identifier (Linux/C++)?

本文关键字:标识符 数字标识 数字 Linux C++ 唯一 路径 转换      更新时间:2023-10-16

我正在研究获取目录(文件夹(并派生某种形式的唯一数字标识符的方法。我研究了"字符串到哈希"方法,但是,鸽子洞原则意味着永远无法为每个字符串导出一个真正唯一的数字。

字符串到唯一哈希是不好的。

我最近一直在研究实现目标的其他方法,因此有以下问题要问:

目录时间戳 - 它们有多"独特"?此处(第二篇文章(中所述的"stat"报告的时间戳分辨率是多少?如果分辨率足够小,是否可以在 Linux 系统上共享多个文件夹完全相同的时间戳?

如果有人有其他方法/技巧想分享,我很乐意听:)

编辑 1 为了澄清我的用例以回应到目前为止发布的答案:我正在 Android 平台上工作,因此文件系统没有链接到任何其他平台(当然,Micro SD 卡等可移动媒体除外(。

我正在将每个路径插入数据库,但在查询表时试图避免字符串比较。在这里,使用地图/哈希图不是一个选项。是的,路径本身是唯一的,但理想情况下,我需要一个可用于查询表的数字标识符,而不是路径本身。每个路径的标识符也必须是唯一的。我尝试过 std::collate,但发现哈希中有很多碰撞(一个包含 20, 000 条路径的数据集大约 100 次碰撞(。更令人惊讶的是,每次运行我的应用程序时,哈希值似乎都大不相同。我想知道它是否以某种方式播种?

非常感谢,P

在任何基于 UNIX 的系统上,都可以使用 inode 编号作为该文件系统中的唯一标识符。将其与设备编号相结合将使其在机器中独一无二。如果您希望它是全局唯一的,则可以输入系统的主MAC地址。

但请记住:

  1. 如果目录被移动或重命名,索引节点号将"跟随"目录。如果删除并替换目录,它将更改。

  2. 索引节点编号在各个系统中都不稳定,除了一两个非常特殊的目录。(例如,/通常是索引节点 2。

+1 黄昏,好一个!

另一种方法是简单地将目录的路径视为一个数字("BigInt"(。

以这个目录为例:/opt/www/log
它有 12 个字符长。
12 * 8位 = 96位
因此,您有一个 96 位长的数字,您可以用 hex/base64/任何东西表示(以防您需要将其作为 HTML 链接传递(。

不过,我个人会选择duskwuff的方法。

我认为这在很大程度上取决于你想要一个唯一的数字标识符的目的。时间戳可以更改,索引节点可以更改,磁盘编号可以更改,MAC 地址可以更改。(不过,黄昏+1

(

在某些情况下,您可以简单地创建一个表,其中您添加的每个路径都会获得一个新的唯一编号,就像数据库中的数字键列一样。

虽然哈希可能会发生冲突,但在每个实际环境中,这绝对是不可能的(如果你不使用最糟糕的算法......由于实现中的缺陷,您更有可能出现错误,例如,您对待"/tmp"与"/tmp/"的方式不同,因为您在散列路径之前没有规范化路径。或者,您想区分物理文件夹,但忘记检查指向同一文件夹的硬链接和符号链接,因此您会为同一目录获得多个哈希/id。

同样,根据您的用例,冲突不一定是致命的:如果您发现新路径产生与现有路径相同的哈希(不会发生!(,您仍然可以对这种情况做出反应。(*)

只是为了帮助你的想象力:如果你使用64位哈希,你可以用空文件夹填充150 000 000个1TB硬盘驱动器(除了短文件夹名称之外什么都没有......(,然后你肯定会发生冲突。如果您认为这风险太大(眨眼,眨眼(,请使用 128 位哈希,使其可能性降低 18 446 744 073 710 000 倍。

哈希被设计成使碰撞不太可能发生,如果没有人愿意尝试产生碰撞,即使是好的旧MD5也会很好地完成它的工作。

(*( 编辑:你的鸽子洞文章已经指出了这一点:碰撞只是意味着查找不再是O(1(,而是稍微慢一点。由于它很少发生,因此您可以轻松地忍受这种情况。如果您使用 std::map(无哈希(或 std::hashmap,则不必担心冲突。看看 STL 中地图和哈希图有什么区别