2008-11-13 16 views
13

Ich arbeite an einem Programm, das ganze Laufwerke für eine bestimmte Datei durchsucht. Im Moment berechne ich einen MD5-Hash für die bekannte Datei und scanne dann alle Dateien rekursiv nach einer Übereinstimmung.Schnellere MD5 Alternative?

Das einzige Problem ist, dass MD5 bei großen Dateien mühsam langsam ist. Gibt es eine schnellere Alternative, die ich verwenden kann, während ich eine sehr kleine Wahrscheinlichkeit von Fehlalarmen behalte?

Der gesamte Code ist in C#.

Vielen Dank.

aktualisieren

ich, dass auch MD5 und dass Scheibe ziemlich schnell sein kann I/O der limitierende Faktor sein sollte, gelesen habe. Das lässt mich glauben, dass mein Code möglicherweise nicht optimal ist. Gibt es Probleme mit diesem Ansatz?

 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

Statt .ToString zu tun ("x2") verwenden http://blogs.msdn.com/b/blambert/archive/2009/02/22/blambert-codesnip -fast-Byte-Array-zu-Hex-String-Konvertierung.aspx, die Sie etwas Zeit sparen. – tcables

+1

Wie heißt "ToLower" und "ToUpper"? –

Antwort

44

Ich hoffe, Sie suchen nur nach einer MD5-Übereinstimmung, wenn die Dateigröße bereits übereinstimmt.

Eine weitere Optimierung besteht darin, eine schnelle Prüfsumme der ersten 1K (oder einer anderen willkürlichen, aber einigermaßen kleinen Zahl) zu erstellen und sicherzustellen, dass diese übereinstimmen, bevor die ganze Datei bearbeitet wird.

Natürlich geht das alles davon aus, dass Sie nur nach einer Übereinstimmung/Nomatch-Entscheidung für eine bestimmte Datei suchen.

+3

+1 für die Scheibe. Keine Notwendigkeit, 37 Gigs zu hashen, wenn das erste Byte anders ist. – Dan

5

nur die Datei linear lesen? Es scheint ziemlich sinnlos zu sein, die gesamte Datei zu lesen, einen MD5-Hash zu berechnen und dann den Hash zu vergleichen.

Wenn Sie die Datei nacheinander lesen, können Sie nach dem Lesen von z. B. 4 Byte die meisten Dateien verwerfen. Und Sie sparen den gesamten Verarbeitungsaufwand für die Berechnung einer Hashfunktion, die Ihnen in Ihrem Fall nichts bringt.

Wenn Sie bereits die Hashes für alle Dateien im Laufwerk hatten, würde es Sinn machen, sie zu vergleichen, aber wenn Sie sie im laufenden Betrieb berechnen müssen, scheint es keinen Vorteil für die Hashing.

Fehle ich hier etwas? Was kostet Hashing in diesem Fall?

+0

Leider habe ich keinen Zugriff auf die Originaldatei, wenn das Programm läuft, so dass das Speichern eines Hash (eigentlich viele Hashes) der einzige Weg ist, den ich vergleichen kann. –

+4

Zumindest, wenn Sie den Hash plus die ersten paar Bytes speichern können (vorzugsweise mehr als 4, weil das ist oft die Größe der Dateiformat magische Zahlen), dann können Sie die überwiegende Mehrheit der Fälle, die nur die Datei geöffnet und lesen ein paar Bytes. –

6

Zuerst überlegen, was wirklich Ihr Flaschenhals ist: die Hash-Funktion selbst oder eher eine Festplattenzugriffsgeschwindigkeit? Wenn Sie von der Festplatte begrenzt sind, gibt Ihnen der Hashing-Algorithmus nicht viel. Aus Ihrer Beschreibung geht hervor, dass Sie immer die gesamte Festplatte scannen, um eine Übereinstimmung zu finden. Ziehen Sie in Erwägung, zuerst den Index zu erstellen und dann nur einen bestimmten Hash mit dem Index abzugleichen. Dies wird viel schneller.

5

Es gibt ein kleines Problem mit MD5-Dateien zu vergleichen: Es sind bekannte Paare von Dateien, die verschiedene sind, aber die gleichen MD5.

Das heißt, Sie MD5 zu sagen, ob die Dateien verschiedene (wenn der MD5 anders ist, müssen die Dateien unterschiedlich sein) verwenden können, aber Sie können nicht MD5 sagen verwenden, wenn die Dateien gleich (wenn das sind Dateien sind gleich, das MD5 muss identisch sein, aber wenn das MD5 gleich ist, sind die Dateien möglicherweise oder nicht identisch).

Sie sollten entweder eine Hash-Funktion verwenden, die noch nicht unterbrochen wurde (wie SHA-1), oder (wie @SoapBox erwähnt) MD5 nur als schnellen Weg verwenden, um Kandidaten für einen tieferen Vergleich zu finden.

Referenzen:

+0

Ich wusste das nie. Vielen Dank! –

+3

Richtig, aber das gilt für das Hashing im Allgemeinen. Wenn der Hash-Wert n Bits lang ist, gibt es nur 2^n mögliche Hash-Werte. Aber die Anzahl der verschiedenen Dateien ist abzählbar unendlich. Somit ist die Anzahl von Paaren verschiedener Dateien, die den gleichen Hash-Wert haben, ebenfalls abzählbar unendlich. – Ingo

+7

@Ingo: Ja, aber für MD5 wissen wir, wie man ein Paar Dateien mit dem gleichen Hash-Wert erstellt (nicht nur das, aber mehrere solcher Paare sind bereits bekannt). Für kryptografische Hashes, die noch nicht zerbrochen sind, können wir ein solches Paar nicht absichtlich erschaffen, und das zufällige Erzeugen hat eine extrem kleine Wahrscheinlichkeit, klein genug, um es so behandeln zu können, als ob es gar nicht möglich wäre (zumindest bis dahin) Hash wird auch kaputt). – CesarB

9

Unabhängig von Verschlüsselungsanforderungen besteht die Möglichkeit einer Hash-Kollision, so dass keine Hash-Funktion zu Garantie verwendet werden kann, dass zwei Dateien identisch sind.

Ich habe vor einiger Zeit einen ähnlichen Code geschrieben, den ich ziemlich schnell ausführen konnte, indem ich zuerst alle Dateien indexierte und alle mit einer anderen Größe verwarf. Ein schneller Hash-Vergleich (für jeden Teil der Datei) wurde dann für die restlichen Einträge durchgeführt (das Vergleichen von Bytes für diesen Schritt erwies sich als weniger nützlich - viele Dateitypen haben gemeinsame Header, die identische Bytes am Anfang der Datei haben). Alle Dateien, die nach dieser Phase übrig waren, wurden dann mit MD5 überprüft und schließlich ein Byte-Vergleich der gesamten Datei, wenn die MD5 übereinstimmte, um sicherzustellen, dass der Inhalt derselbe war.

+0

Klingt nach einer guten, logischen Herangehensweise - danke für das Einspielen. –

0

Verwenden MD5CryptoServiceProvider und 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); 
      } 
     } 
+2

-1: Das beschleunigt den Prozess nicht. Um es schneller zu machen, funktioniert nur die ** fünf Jahre alte, akzeptierte und hoch aufgeschlagene Antwort **. – Oliver