用于确定文件身份的算法

时间:2009-01-19 00:05:25

标签: algorithm filesystems virtualfilesystem

对于一个开源项目,我要在文件系统之上编写一个抽象层。

此图层允许我将元数据和关系附加到每个文件。

我希望图层能够正常地重命名文件并在重命名/移动或复制文件时维护元数据。

为此,我需要一种计算文件身份的机制。显而易见的解决方案是为每个文件计算SHA1哈希值,然后根据该哈希值分配元数据。但是......这真的很贵,特别是对于电影来说。

所以,我一直在考虑一种算法虽然不是100%正确,但绝大多数时候都是正确的,并且很便宜。

一种这样的算法可以是使用文件大小和该文件的字节样本来计算散列。

我应该为样本选择哪些字节?如何保持计算的便宜和合理准确?我知道这里有一个权衡,但性能至关重要。用户将能够处理系统出错的情况。

我需要这个算法适用于非常大的文件(1GB +和小文件5K)

编辑

我需要这个算法来处理NTFS和所有SMB共享(基于Linux或基于Windows),我希望它支持将文件从一个位置复制到另一个位置的情况(存在2个物理副本被视为一个标识) 。我甚至可能会考虑在需要重新标记MP3的情况下(物理文件已更改,因此我可能每个文件类型都有一个身份提供程序)。

编辑2

相关问题:Algorithm for determining a file’s identity (Optimisation)

8 个答案:

答案 0 :(得分:5)

暂停,多层比较应该是您正在讨论的文件范围内最快且可扩展的。

第一级索引只是文件的长度。

第二级是哈希。低于一定大小,它是一个完整的文件哈希。除此之外,是的,我同意你对采样算法的看法。我认为可能会影响采样速度的问题:

  1. 为避免碰到规则间隔的标题,这些标题可能高度相似或相同,您需要输入一个不合格的数字,例如:素数或连续素数的倍数。
  2. 避免可能最终遇到常规记录标题的步骤,因此如果您从不同位置的示例字节中获取相同的值,请尝试通过另一个素数调整步骤。
  3. 处理具有大量相同值的异常文件,因为它们是未编码的图像或只是填充空值。

答案 1 :(得分:4)

第一个128k,另一个128k在1mb标记,另一个128k在10mb标记,另外128k在100mb标记,另外128k在1000mb标记等。随着文件大小变大,它变得更有可能你可以根据它们的大小来区分两个文件,你可以散列越来越小的数据。 128k以下的所有东西都完全得到了照顾。

答案 2 :(得分:2)

信不信由你,我使用滴答作为文件的最后写入时间。它虽然便宜,但我仍然看到不同文件之间的冲突。

答案 3 :(得分:2)

如果您可以放弃Linux共享要求并将自己限制在NTFS,那么NTFS备用数据流将是一个完美的解决方案:

  • 不需要任何散列;
  • 幸存重命名;和
  • 幸存下来(甚至在不同的NTFS卷之间)。

您可以阅读更多相关信息here。基本上你只需为你的流附加一个冒号和一个名字(例如“:meta”)并写下你喜欢的任何内容。因此,如果您有一个目录“D:\ Movies \ Terminator”,请使用普通文件I / O将元数据写入“D:\ Movies \ Terminator:meta”。如果要保存特定文件的元数据(而不是整个文件夹),也可以这样做。

如果您希望将元数据存储在其他位置,并且能够检测同一NTFS卷上的移动/重命名,则可以使用GetFileInformationByHandle API调用(请参阅MSDN / en-us / library / aa364952(VS。 85).aspx)获取文件夹的唯一ID(组合VolumeSerialNumber和FileIndex成员)。如果在同一卷上移动/重命名文件/文件夹,则此ID不会更改。

答案 4 :(得分:1)

如何存储一些随机整数r i ,并查找字节(r i mod n),其中n是文件的大小?对于带有标题的文件,您可以先忽略它们,然后对剩余的字节执行此过程。

如果您的文件实际上非常不同(不仅仅是某个字节的差异,但至少有1%不同),那么随机选择的字节会注意到这一点。例如,如果字节差异为1%,则100个随机字节将无法通知,概率为1 / e~37%;增加你看到的字节数会使这个概率呈指数下降。

使用随机字节背后的想法是它们基本上得到保证(好的,概率上讲)与任何其他字节序列一样好,除非它们易受某些问题的影响与其他序列(例如,发现查看文件格式的每个第256个字节,其中该字节需要为0或其他)。

更多建议:

  • 不要抓取字节,而是抓住更大的块来证明寻求成本的合理性。
  • 我建议总是查看文件的第一个块左右。从这里,您可以确定文件类型等。 (例如,您可以使用file程序。)
  • 至少权衡像整个文件的CRC这样的成本/收益。它不像真正的加密哈希函数那么昂贵,但仍然需要读取整个文件。好处是注意到单字节差异。

答案 5 :(得分:0)

首先,您需要更深入地了解文件系统的工作方式。您将使用哪些文件系统?大多数文件系统都支持硬链接和软链接等内容,因此“文件名”信息不一定存储在文件本身的元数据中。

实际上,这是可堆叠分层文件系统的重点,您可以通过各种方式扩展它,比如支持压缩或加密。这就是“vnodes”的全部内容。你可以用几种方式实现这一点。其中一些非常依赖于您正在查看的平台。在使用VFS概念的UNIX / Linux系统上,这更加简单。例如,你可以在ext3的tope上实现你自己的图层,或者你有什么。

** 阅读完你的编辑后,会发生更多事情。如前所述,文件系统已经使用像inode之类的东西来做这件事。哈希可能不是一个坏主意,不仅因为它很昂贵,而且因为两个或多个preimages可以共享相同的图像;也就是说两个完全不同的文件可以具有相同的散列值。我认为你真正想要做的是利用文件系统已经暴露的元数据。当然,这在开源系统上会更简单。 :)

答案 6 :(得分:0)

  

我应该为样本选择哪个字节?

我认为我会尝试使用像Fibonacci数字这样的算术级数。这些很容易计算,密度也在减小。小文件的采样率比大文件高,样本仍然会覆盖整个文件中的点。

答案 7 :(得分:0)

这项工作听起来好像可以在文件系统级别更有效地实现,或者使用一些版本控制系统的松散近似(两者兼而有之)。

要解决原始问题,您可以为每个文件保留(文件大小,字节散列,散列)数据库,并尝试最小化每个文件大小的散列字节数。每当您检测到碰撞时,您要么拥有相同的文件,要么增加哈希长度以超越第一个差异。

毫无疑问,优化和CPU与I / O之间的权衡也是如此,但对于没有误报的事情来说,这是一个良好的开端。