2009-11-23 37 views
5

Estoy intentando hacer un seguimiento de un conjunto de archivos, que pueden tener el mismo nombre y metadatos. Me gustaría utilizar un hash para diferenciarlo y usarlo como una identificación única, pero no estoy seguro de cuál usar. Los archivos son relativamente pequeños (en el rango de 100 kb) y me gustaría poder hacer hash en menos de 10 segundos. ¿Qué hash (que viene incorporado en Java 1.5) sería lo mejor para mis necesidades?Qué hash usar para la exclusividad de archivos en Java

Respuesta

15

Tenga en cuenta que un hash de este tipo será nunca sea único, sin embargo, con el uso de uno efectivo tiene una muy buena probabilidad de nunca tener una colisión.

Si no le preocupa la seguridad (es decir, alguien que intente deliberadamente romper su hashing), simplemente usar el hash MD5 le dará un excelente hash con un mínimo esfuerzo.

Es probable que pueda hacer un hash SHA de 100 Kb en menos de 10 segundos y, aunque SHA-1 todavía tiene defectos teóricos, es de mayor resistencia que MD5.

MessageDigest obtendrá una implementación de cualquiera.

Éstos son algunos examples of using it with streams.

También debo señalar que this excellent answer from jarnbjo indicaría que incluso el hash SHA suministrado en Java es capaz de exceder los 20 MB/s incluso en hardware x86 relativamente modesto. Esto implicaría 5-10 milisegundo rendimiento de nivel en 100KB de datos de entrada (en memoria) por lo que su objetivo de menos de 10 segundos es una sobreestimación masiva del esfuerzo involucrado. Es probable que esté completamente limitado por la velocidad con la que puede leer los archivos del disco en lugar de cualquier algoritmo de hash que utilice.

Si necesita fuerte cripto hashing, debe indicarlo en la pregunta. Incluso entonces SHA de algún sabor por encima de 1 todavía es probable que sea su mejor opción a menos que desee usar una biblioteca externa como Bouncy Castle, ya que nunca debe intentar rodar su propia cripto si existe una implementación bien establecida.

Para algunos ejemplos de código razonablemente eficiente que sugieren this how to Los puntos más importantes de las cuales se puede destilar en la siguiente (ajustar el tamaño del búfer como mejor le parezca):

import java.io.*; 
import java.security.MessageDigest; 

public class Checksum 
{  
    const string Algorithm = "SHA-1"; // or MD5 etc. 

    public static byte[] createChecksum(String filename) throws 
     Exception 
    { 
     InputStream fis = new FileInputStream(filename); 
     try 
     { 
      byte[] buffer = new byte[1024]; 
      MessageDigest complete = MessageDigest.getInstance("MD5"); 
      int numRead; 
      do 
      { 
       numRead = fis.read(buffer); 
       if (numRead > 0) 
       { 
        complete.update(buffer, 0, numRead); 
       } 
      } while (numRead != -1); 
      return complete.digest(); 
     } 
     finally 
     { 
      fis.close(); 
     } 
    } 
} 
+1

+1 para la nota de que los hashes nunca serán únicos. – PSpeed

+0

Excelente respuesta por todas partes, gracias. –

0

use un hash basado en contenido SHA1 es lo que uso. MD5 es más débil y más rápido, pero en los procesadores modernos la velocidad no es una preocupación.

5

podría utilizar MessageDigest con SHA1:

MessageDigest messageDigest = MessageDigest.getInstance("SHA1"); 
    InputStream is = new FileInputStream(aFile); 
    int res; 

    while ((res = inputStream.read()) != -1) { 
     digester.update((byte) res); 
    } 

    byte[] digest = messageDigest.digest(); 
+0

@downvoter: explique su voto negativo o no tiene sentido – dfa

+0

no hay pista, pero es una respuesta razonable, así que aquí hay un +1 para compensar – ShuggyCoUk

0

aquí es la manera de hacerlo, creo que esto debería funcionar rápido, comprobar si se completa en 10 segundos

package utils; 

import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 

/** 
* This class used to compute the hash value of any string 
*/ 
public class MyHasher { 
private static final String ALGORITHM = "MD5"; 
static MessageDigest md = null; 

static{ 
    try { 
     md = MessageDigest.getInstance(ALGORITHM); 
    } catch (NoSuchAlgorithmException e) { 
     MyLogger.error("Can't find implementation of "+ALGORITHM+" algorithm", e); 
    } 
} 

/** 
* Compute hash value of any string 
* @param arg the string to compute hash value of. 
* @return the hex hash value as a string. 
*/ 
public static String getHash(String arg) { 
    md.update(arg.getBytes()); 
    byte[] hashValue = md.digest(); 

    return convertToHex(hashValue); 
} 
/** 
* Converts byte array to the human readable string of hex'es 
* @param data the byte array to convert 
* @return string representation of the hex'es of the byte array 
*/ 
public static String convertToHex(byte[] data){ 
    StringBuffer buf = new StringBuffer(); 
    for(int i=0;i<data.length;i++){ 
     int halfbyte = (data[i]>>>3)&0x0F; 
     int two_halfs = 0; 
     do{ 
      if((0<=halfbyte) && (halfbyte <=9)) 
       buf.append((char) ('0'+halfbyte)); 
      else 
       buf.append((char) ('a'+(halfbyte-10))); 
      halfbyte = data[i] & 0x0F; 
     }while(two_halfs++ <1); 
    }  
    return buf.toString(); 
} 
} 
+0

Agregaría la condición a esto que obliga a leer todo el archivo en la memoria a través de una cadena es es probable que sea ineficiente, requiera más memoria de la necesaria y tenga implicaciones si quisiera copiar un archivo ASCIi como bytes sin formato en lugar de forzarlo a que se convierta primero en caracteres anchos (por ejemplo, si desea que una herramienta estándar externa también lo pueda usar)) – ShuggyCoUk

Cuestiones relacionadas