【问题标题】:Algorithm for determining a file’s identity (Optimisation)确定文件身份的算法(优化)
【发布时间】:2010-10-21 18:51:29
【问题描述】:

进一步回答这个问题:Algorithm for determining a file’s identity

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

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

我的算法的工作方式是:

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

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

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

问题:

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

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

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

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

相关信息:

The algorithm I implemented

感谢您的帮助!

【问题讨论】:

  • 吹毛求疵:签名!?你的意思是签名?

标签: c# optimization identity


【解决方案1】:

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

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

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

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

对于较大的文件,文件长度冲突的可能性会降低,因为可能的文件长度越来越多。对于不同的媒体文件,它们很可能直接在标题之外有所不同,因此您只需对文件开头的一小部分进行哈希处理。

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

更新

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

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

【讨论】:

  • RE:“如果您看到一个具有唯一文件长度的新文件”,这是一个非常棘手的问题,因为它可能是原始文件并且它移动到了其他地方。我同意该算法不是 100% 安全的,但我发现它实际上不可能在真实视频(DVD / AVI 等)上失败。我认为这是一个很好的第一级散列,并且比长度更健壮一个人。
  • 对于电影,我认为文件长度实用独特。你有两个大小相同的不同文件吗?好的,如果重新编码以适应给定的媒体,可能是 - (S)VCD 电影都将在一个小范围的文件长度内。但是对于媒体文件,我只会从文件中间散列一个块(可能是 512 字节)。两部不同的电影在同一位置具有相同的图像和声音?除了您操纵文件以使此测试失败之外,几乎不可能。
【解决方案2】:
  1. 不要向后搜索并使用 FILE_FLAG_SEQUENTIAL_SCAN 打开文件(在 Windows 上)。
    (选择 X 个随机数,然后对它们进行排序)。
  2. 为了寻求更远,预读缓存中通常有一些数据。
  3. 如果您有大文件,请将您的分区格式化为具有大扇区大小。
  4. 您为 Id 返回一个 Guid,哈希算法必须超过 128 位。

【讨论】:

  • 修正了错字:) 解决方案对位置进行排序,所以我不会向后寻找......我该如何在.Net中设置FILE_FLAG_SEQUENTIAL_SCAN?我真的无法访问 C# 中的低级信息...
  • Lowlevel (AFAIK),使用 CreateFile(pinvoke.net 是你的朋友)并使用除 IntPtr 之外的 ctor。
  • 哎呀痛苦 :) 我会获得什么样的性能优势,它会快 2 倍吗?
  • 顺便说一句,MD5 非常适合一个非常方便的 Guid
  • 我无法告诉您它会快多少(如果有的话),这取决于您的操作系统、驱动器和驱动程序。我看到 x1.5 到 x5(和 x0...)从使用它中获益。 MD5 很弱,不应该再使用了。
【解决方案3】:
  • 始终在哈希中包含第一个和最后一个文件块。

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

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

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

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

【讨论】:

  • 第一个和最后一个块是一个有趣的优化(针对特定格式进行优化的想法非常吸引人,例如 VOB 在这种情况下是有问题的)。关于读取可分割块,我想这有助于提供 FS 没有碎片化。是的,深度扫描的想法可能是一个很好的技巧,可以确保这真的永远不会失败。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-30
  • 2023-02-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多