2008-11-13 28 views
13

Estoy trabajando en un programa que busca unidades enteras para un archivo determinado. Por el momento, calculo un hash MD5 para el archivo conocido y luego escaneo todos los archivos recursivamente, buscando una coincidencia.¿Una alternativa más rápida a MD5?

El único problema es que MD5 es extremadamente lento en archivos grandes. ¿Existe una alternativa más rápida que pueda usar, manteniendo una probabilidad muy pequeña de falsos positivos?

Todo el código está en C#.

Gracias.

actualización

He leído que incluso MD5 puede ser bastante rápido y que el disco E/S debería ser el factor limitante. Eso me lleva a creer que mi código podría no ser óptimo. ¿Hay algún problema con este enfoque?

 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

En vez de hacer .ToString ("x2") utilizan http://blogs.msdn.com/b/blambert/archive/2009/02/22/blambert-codesnip -fast-byte-array-to-hex-string-conversion.aspx que le ahorrará tiempo. – tcables

+1

¿Cuál es el punto de llamar 'ToLower' y' ToUpper'? –

Respuesta

44

Espero que esté buscando una coincidencia MD5 solo si el tamaño del archivo ya coincide.

Otra optimización es hacer una suma de comprobación rápida del primer 1K (o algún otro número arbitrario, pero razonablemente pequeño) y asegúrese de que coincidan antes de trabajar todo el archivo.

Por supuesto, todo esto supone que solo está buscando una decisión de coincidencia/nominación para un archivo en particular.

+3

+1 para la porción. No hay necesidad de hash 37 conciertos, cuando el primer byte es diferente. – Dan

5

¿acaba de leer el archivo de forma lineal? Parece bastante inútil leer el archivo completo, calcular un hash md5 y luego comparar el hash.

Leer el archivo secuencialmente, unos pocos bytes a la vez, le permitiría descartar la gran mayoría de los archivos después de leer, digamos, 4 bytes. Y ahorrará todos los gastos generales de procesamiento al computar una función de hashing que no le da nada en su caso.

Si ya tenía los valores hash para todos los archivos en la unidad, tendría sentido compararlos, pero si tiene que calcularlos sobre la marcha, simplemente no parece haber ninguna ventaja para la hashing.

Me estoy perdiendo algo aquí? ¿Qué te compra hashing en este caso?

+0

Lamentablemente, no tendré acceso al archivo original cuando se ejecuta el programa, por lo que almacenar un hash (en realidad muchos hash) es la única forma en que puedo comparar. –

+4

Por lo menos, si puede almacenar el hash más los primeros bytes (preferiblemente más de 4 porque a menudo ese es el tamaño de los números mágicos de formato de archivo), puede descartar la gran mayoría de los casos que solo abrieron el archivo y leyeron unos pocos bytes –

6

Primero considere cuál es realmente su cuello de botella: la función de hash en sí o más bien una velocidad de acceso al disco? Si está delimitado por un disco, cambiar el algoritmo hash no le dará mucho. Según su descripción, insinúo que siempre está escaneando todo el disco para encontrar una coincidencia: considere construir primero el índice y luego solo haga coincidir un hash dado con el índice, esto será mucho más rápido.

5

Hay un pequeño problema con el uso de MD5 para comparar los archivos: se conocen pares de archivos que se diferente, pero tienen la misma MD5.

Esto significa que puede utilizar MD5 para saber si los archivos son diferente (si el MD5 es diferente, los archivos deben ser diferentes), pero no puede utilizar MD5 para saber si los archivos son igual (si el los archivos son iguales, el MD5 debe ser el mismo, pero si el MD5 es igual, los archivos pueden ser iguales o no).

Debe utilizar una función hash que no se haya roto aún (como SHA-1) o (como se menciona en @SoapBox) usar MD5 solo como una forma rápida de encontrar candidatos para una comparación más profunda.

Referencias:

+0

Nunca lo supe. ¡Gracias! –

+3

Correcto, pero esto se aplica al hash en general. Cuando el hash es n Bits long, solo hay 2^n posibles valores hash. Pero la cantidad de archivos diferentes es infinitamente infinita. Por lo tanto, el número de pares de archivos diferentes que tienen el mismo valor hash también es contablemente infinito. – Ingo

+7

@Ingo: sí, pero para MD5, sabemos cómo crear un par de archivos con el mismo valor hash (no solo eso, sino que ya se conocen varios de esos pares). Para los hashes criptográficos que aún no se han roto, no podemos crear dicho par a propósito, y crearlo por accidente tiene una probabilidad extremadamente pequeña, lo suficientemente pequeña como para que podamos tratarla como si no fuera posible (al menos hasta que eso ocurra). el hash se rompe también). – CesarB

9

que sean las necesidades criptográficas, existe la posibilidad de una colisión de hash, así que no hay función hash puede ser utilizado para garantía de que los dos archivos son idénticos.

Hace un tiempo escribí un código similar el cual tuve que ejecutar bastante rápido indexando primero todos los archivos y descartándolos con un tamaño diferente. Luego se realizó una comparación rápida de hash (en una parte de cada archivo) en las entradas restantes (se comprobó que la comparación de bytes para este paso es menos útil; muchos tipos de archivos tienen encabezados comunes que tienen bytes idénticos al principio del archivo). Todos los archivos que quedaron después de esta etapa se verificaron utilizando MD5, y finalmente una comparación de bytes del archivo completo si el MD5 coincidía, solo para garantizar que el contenido fuera el mismo.

+0

Suena como un buen enfoque lógico, gracias por sonar. –

0

Uso MD5CryptoServiceProvider y 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: Esto no hace que el proceso sea más rápido. Para que sea más rápido, solo funcionará la respuesta de ** cinco años de antigüedad, aceptada y con un voto elevado alto **. – Oliver

Cuestiones relacionadas