6

对此问题的进一步说明:确定文件身份的算法

回顾:我正在寻找一种廉价的算法来确定在绝大多数时间都有效的文件身份。

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

我的算法的工作方式是:

  • 对于小于某个阈值的文件,我使用完整文件内容作为身份哈希。

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

  • 我将文件大小包含在散列数据中。(意味着所有不同大小的文件都会产生不同的哈希值)

问题:

  • 我应该为 N 和 X 选择什么值(我应该取多少个随机样本,大小是多少?)我选择了 4 个 8K 的样本,但无法验证算法。我发现快速增加样本量会降低算法的速度(因为搜索非常昂贵)

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

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

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

相关信息:

我实现的算法

谢谢你的帮助!

4

3 回答 3

1

我会避免这样的解决方案。我认为两个媒体文件在压缩格式的对应位置具有相同的大小和相同的数据可能几乎是不可能的。但是,如果您必须处理未压缩的图像或波形文件,则无法检测到小的本地更改的可能性会增加。

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

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

关于表演的一些想法。对于小文件,相同文件长度的机会非常高 - 没有那么多不同的小文件长度。但是散列小文件并不昂贵。

对于较大的文件,文件长度冲突的机会随着可能的文件长度越来越多而下降。对于不同的媒体文件,它们在标题之外直接不同的可能性非常大,因此您只需要对文件开头的一小部分进行哈希处理。

最后,您一定会检测到不同的文件(哈希冲突除外),因为如果需要,您将对整个文件进行哈希处理。

更新

对于电影,我认为文件长度实际上是独一无二的,但是重新编码以适应给定介质的文件可能会使这个想法无效 - (S)VCD 电影都将在大约 CD-ROM 容量的小文件长度范围内。

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

于 2009-04-25T12:16:13.013 回答
1
  • 始终在哈希中包含第一个和最后一个文件块。

这是因为它们很可能因文件而异。如果您考虑 BMP,它可能具有相当标准的标头(例如 800x600 图像、24 位、空余),因此您可能希望稍微过冲标头以获取差异化数据。问题是标题的大小差异很大。

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

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

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

于 2009-04-25T12:33:21.867 回答
0
  1. 不要向后搜索并使用 FILE_FLAG_SEQUENTIAL_SCAN(在 Windows 上)打开文件。
    (选择 X 个随机数,然后对它们进行排序)。
  2. 为了寻求更远,预读缓存中通常有一些数据。
  3. 如果您有大文件,请将您的分区格式化为具有大扇区大小。
  4. 您为 Id 返回一个 Guid,必须哈希算法需要超过 128 位。
于 2009-04-25T12:16:47.630 回答