2008-11-13 2 views
13

Я работаю над программой, которая ищет все диски для данного файла. На данный момент я вычисляю хэш MD5 для известного файла, а затем просматриваю все файлы рекурсивно, ища совпадение.Более быстрая альтернатива MD5?

Единственная проблема заключается в том, что MD5 болезненно медленный на больших файлах. Есть ли более быстрая альтернатива, которую я могу использовать, сохраняя при этом очень небольшую вероятность ложных срабатываний?

Весь код находится на C#.

спасибо.

Update

Я читал, что даже MD5 может быть довольно быстрым и дискового ввода/вывода должен быть ограничивающим фактором. Это заставляет меня думать, что мой код может быть не оптимальным. Есть ли проблемы с этим подходом?

 MD5 md5 = MD5.Create(); 
     StringBuilder sb = new StringBuilder(); 
     try 
     { 
      using (FileStream fs = File.Open(fileName, FileMode.Open, FileAccess.Read)) 
      { 
       foreach (byte b in md5.ComputeHash(fs)) 
        sb.Append(b.ToString("X2")); 
      } 
      return sb.ToString(); 
     } 
     catch (Exception) 
     { 
      return ""; 
     } 
+2

Вместо того чтобы делать .ToString ("x2") использовать http://blogs.msdn.com/b/blambert/archive/2009/02/22/blambert-codesnip -fast-byte-array-to-hex-string-conversion.aspx, что сэкономит вам некоторое время. – tcables 2011-01-20 19:18:54

+1

В чем смысл вызова `ToLower` и` ToUpper`? – 2013-09-28 17:38:44

ответ

44

Надеюсь, вы проверяете соответствие MD5, только если размер файла уже совпадает.

Другая оптимизация - сделать быструю контрольную сумму первого 1K (или какого-либо другого произвольного, но достаточно маленького числа) и убедиться, что они совпадают, прежде чем работать со всем файлом.

Конечно, все это предполагает, что вы ищете решение match/nomatch для определенного файла.

+3

+1 для ломтика. Нет необходимости делать хеш 37 концертов, когда первый байт отличается. – Dan 2013-11-14 14:14:39

5

просто читайте файл линейно? Кажется довольно бессмысленным читать весь файл, вычислять хеш md5, а затем сравнивать хэш.

Чтение файла последовательно, несколько байтов за раз, позволит вам отбросить подавляющее большинство файлов после чтения, скажем, 4 байта. И вы сохраните все накладные расходы на обработку вычислительной функции хеширования, которая не даст вам ничего в вашем случае.

Если у вас уже есть хэши для всех файлов на диске, имеет смысл сравнить их, но если вам нужно их вычислить на лету, просто не кажется, хэширования.

Я что-то упустил? Что вы хотите купить в этом случае?

+0

К сожалению, у меня не будет доступа к исходному файлу, когда программа работает, поэтому сохранение хэша (на самом деле много хэшей) - единственный способ сравнить. – 2008-11-13 23:34:53

+4

По крайней мере, если вы можете сохранить хеш плюс первые несколько байтов (желательно более 4, потому что часто это размер магических чисел формата файла), тогда вы можете отбросить подавляющее большинство случаев, только открыв файл и прочитав несколько байтов. – 2008-11-14 02:00:17

6

Сначала рассмотрите, что на самом деле является вашим узким местом: сама хеш-функция или, скорее, скорость доступа к диску? Если вы ограничены диском, изменение алгоритма хэширования не даст вам многого. Из вашего описания я подразумеваю, что вы всегда просматриваете весь диск, чтобы найти совпадение - подумайте о том, чтобы сначала создать индекс, а затем только соответствовать заданному хешу против индекса, это будет намного быстрее.

5

Существует одна небольшая проблема с использованием MD5 для сравнения файлов: есть известные пары файлов, которые другое но имеют же MD5.

Это означает, что вы можете использовать MD5 сказать, если файлы разных (если MD5 отличается, файлы должны быть разными), но вы не можете использовать MD5, чтобы сказать, если файлы равного (если файлы равны, MD5 должен быть одинаковым, но если MD5 равен, файлы могут быть или не быть равными).

Вы должны либо использовать хеш-функцию, которая еще не была сломана (например, SHA-1), либо (как упоминалось в @SoapBox) использовать MD5 только как быстрый способ найти кандидатов для более глубокого сравнения.

Ссылки:

+0

Я этого никогда не знал. Спасибо! – 2008-11-13 23:48:31

9

Независимо от криптографических требований, возможность хэш столкновения существует, поэтому никакая функция хеширования не может быть использована для гарантии, что два файла идентичны.

Я написал аналогичный код некоторое время назад, которое я получил, чтобы работать довольно быстро, сначала индексируя все файлы и отбрасывая любой другой размер. Затем было выполнено быстрое сравнение хэша (по части каждого файла) на остальных элементах (сравнение байтов для этого шага оказалось менее полезным - многие типы файлов имеют общие заголовки с одинаковыми байтами в начале файла). Любые файлы, оставшиеся после этого этапа, затем проверялись с использованием MD5 и, наконец, байтовое сравнение всего файла, если MD5 соответствовал, чтобы гарантировать, что содержимое было одинаковым.

0

Использование MD5CryptoServiceProvider и BufferedStream

 using (FileStream stream = File.OpenRead(filePath)) 
     { 
      using (var bufferedStream = new BufferedStream(stream, 1024 * 32)) 
      { 
       var sha = new MD5CryptoServiceProvider(); 
       byte[] checksum = sha.ComputeHash(bufferedStream); 
       return BitConverter.ToString(checksum).Replace("-", String.Empty); 
      } 
     }