确定文件标识的算法(优化)

继这个问题: 用于确定文件身份的算法

回顾 :我正在寻找一种用于确定文件标识的廉价算法,该算法在绝大多数情况下都有效。

我继续并实现了一种算法,它为每个文件提供了“ 非常独特 ”的哈希值。

我的算法的工作方式是:

  • 对于小于特定阈值的文件,我使用标识哈希的完整文件内容。

  • 对于大于阈值的文件,我采用X大小的随机N个样本。

  • 我将文件大小包含在散列数据中。 (意味着具有不同大小的所有文件导致不同的哈希)

问题:

  • 我应该为N和X选择什么值(我应该选择多少随机样本的大小?)我选择了4个样本,每个8K,并且不能算法算法。 我发现增加样本量会迅速降低算法的速度(导致搜索非常昂贵)

  • 数学一:我的文件需要多少才能让这个算法爆炸。 (2个具有相同长度的不同文件最终具有相同的哈希值)

  • 优化一:有什么方法可以优化我的具体实现来提高吞吐量(我似乎能够在我的系统上每秒做大约100个文件)。

  • 这个实现看起来是否合理? 你能想到任何真实世界的例子吗? (我的重点是媒体文件)

相关信息:

我实现的算法

谢谢你的帮助!

  • 始终在哈希中包含第一个和最后一个文件块。

这是因为它们最有可能与文件不同。 如果你考虑BMP,它可能有相当标准的标题(如800×600图像,24位,空值rest),所以你可能想要稍微超过标题以获得差异化数据。 问题是标题的大小差别很大。

最后一个块用于将数据附加到原始文件的文件格式。

  • 读入您使用的文件系统本机大小的块,或者至少可以被512整除。
  • 始终读取可被blocksize整除的偏移量的块。
  • 如果你对相同大小的文件有相同的权限,请对其进行深度扫描(散列所有数据)并记住文件路径以不再扫描它。

即便如此,除非你很幸运,否则你会错误地将一些文件识别为相同的文件(例如SQL Server数据库文件,并且只需几次插入后它就是1:1备份副本;除了SS确实写了一个时间戳…)

我会避免像这样的解决方案。 我认为,两个媒体文件在压缩格式的相应位置具有相同的大小和相同的数据可能接近于不可能。 但是如果你必须处理未压缩的图像或波形文件,那么未检测到小的局部变化的可能性就会增大。

所以我认为你应该重新散列整个文件。 虽然这看起来很昂贵但是如果您可以访问所有文件可能不会 – 例如,如果您构建文件服务器或类似的东西。 您可以逐步构建哈希值。

如果您看到具有唯一文件长度的新文件,则只需存储文件长度。 如果添加了另一个具有相同长度的文件,则逐块计算两个文件的哈希值,直到它们不同为止。 存储文件长度,散列以及散列中包含的文件块数。 每当您检测到匹配的文件长度和哈希值并且尚未散列整个文件时,您可以通过添加更多块来扩展哈希值。

关于表现的一些想法。 对于小文件,相同文件长度的可能性非常高 – 没有那么多不同的小文件长度。 但是散列小文件并不昂贵。

对于较大的文件,由于文件长度越来越多,文件长度碰撞的可能性会下降。 对于不同的媒体文件,它们直接超出标题的可能性非常大,因此您只需要对文件开头的一小部分进行哈希处理。

最后,您将确保检测不同的文件(散列冲突除外),因为如果需要,您将散列整个文件。

UPDATE

对于电影我会认为文件长度实用独特,但重新编码以适合给定媒体的文件可能使这个想法无效 – (S)VCD电影将全部在一小部分文件长度约CD-ROM容量。

但对于一般的电影文件,我只是从文件中间散列一个块(可能是512字节)。 两个不同的电影在同一位置具有相同的图像和声音? 除了你操纵文件以使这个测试失败之外,实际上是不可能的。 但是您可以轻松生成文件以使所有确定性采样策略失败 – 所以这应该不重要。

  1. 不要向后搜索并使用FILE_FLAG_SEQUENTIAL_SCAN(在Windows上)打开文件。
    (选择X随机数,然后对它们进行排序)。
  2. 为了寻求远,在预读缓存中通常会有一些数据。
  3. 如果您有大文件格式您的分区具有大扇区大小。
  4. 你返回ID的Guid,Must哈希算法需要128位以上。