2012-04-26 12 views
5

Estoy tratando de diseñar una aplicación simple que se utilizará para calcular un archivo CRC32/md5/sha1/sha256/sha384/sha512, y me he encontrado con un obstáculo. Esto se está haciendo en C#.¿Cómo hash un único archivo de varias maneras al mismo tiempo?

Me gustaría poder hacer esto de la manera más eficiente posible, así que mi idea original fue leer el archivo en una corriente de memoria antes del procesamiento, pero pronto descubrí que los archivos muy grandes me hacían falta memoria muy rápidamente. Entonces parece que tengo que usar un filestream en su lugar. El problema, según lo veo, es que solo se puede ejecutar una función hash a la vez, y hacerlo con una cadena de archivos tardará un tiempo en completarse.

¿Cómo puedo leer un pequeño archivo en la memoria, procesarlo con los 6 algoritmos y luego ir a otro fragmento ... O el hash no funciona de esa manera?

Este fue mi intento original de leer un archivo en la memoria. Fracasó cuando traté de leer una imagen de CD en la memoria antes de ejecutar los algoritmos hash en la MemoryStream: algoritmos

private void ReadToEndOfFile(string filename) 
    { 
     if (File.Exists(filename)) 
     { 
      FileInfo fi = new FileInfo(filename); 
      FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read); 
      byte[] buffer = new byte[16 * 1024]; 

      //double step = Math.Floor((double)fi.Length/(double)100); 

      this.toolStripStatusLabel1.Text = "Reading File..."; 
      this.toolStripProgressBar1.Maximum = (int)(fs.Length/buffer.Length); 
      this.toolStripProgressBar1.Value = 0; 

      using (MemoryStream ms = new MemoryStream()) 
      { 
       int read; 
       while ((read = fs.Read(buffer, 0, buffer.Length)) > 0) 
       { 
        ms.Write(buffer, 0, read); 
        this.toolStripProgressBar1.Value += 1; 
       } 

       _ms = ms; 
      } 
     } 
    } 

Respuesta

3

Está todo el camino hasta allí, simplemente no necesita leer todo en la memoria a la vez.

Todos los valores hash en .Net derivan de la clase HashAlgorithm. Tiene dos métodos: TransformBlock y TransformFinalBlock. Por lo tanto, debería poder leer un fragmento para su archivo, rellenarlo con el método TransformBlock de los hashes que quiera usar y luego pasar al siguiente bloque. Simplemente recuerde llamar al TransformFinalBlock para obtener su último fragmento del archivo, ya que eso es lo que le proporciona la matriz de bytes que contiene el hash.

Por ahora, sólo haría cada uno de hash uno a la vez, hasta que se está trabajando, y luego preocuparse por quedarse los hashes simultáneamente (usando algo como la Biblioteca paralelo de tareas)

+0

He intentado hacer que esto funcione con MD5, y el programa se ejecuta, aunque parece que está generando valores hash incorrectos. Aquí hay un enlace a mi código: [link] (http://pastebin.com/i3iPwYZv) – agent154

+1

Deberías usar 'read' en lugar de' buffer.Length' cuando llamas 'TransformFinalBlock' –

+0

¡Muchas gracias! Estaba angustiado por esto por un tiempo anoche. Terminé pirateando algo estúpido buscando que funcionara, pero no pude evitar sentir que era innecesario. Descubrí que era porque el último conjunto se estaba leyendo completamente, incluso cuando el último fragmento era demasiado pequeño para él. Terminé creando una nueva matriz de bytes para que la última pieza igualara el tamaño del último fragmento. – agent154

4

Hash están diseñados de una manera que se puede calcular el valor hash de forma incremental. Puede encontrar un ejemplo C# /. NET para ese here. Puede modificar fácilmente el código proporcionado para actualizar múltiples instancias de algoritmo hash en cada paso.

0

Esto podría ser una gran oportunidad para obtener sus pies mojados con los objetos de flujo de datos TPL. Lea el archivo en un hilo y publique los datos en un BroadcastBlock<T>. El BroadcastBlock<T> se vinculará a 6 instancias diferentes ActionBlock<T>. Cada ActionBlock<T> corresponderá a una de sus 6 estrategias hash.

var broadcast = new BroadcastBlock<byte[]>(x => x); 

var strategy1 = new ActionBlock<byte[]>(input => DoHash(input, SHA1.Create())); 
var strategy2 = new ActionBlock<byte[]>(input => DoHash(input, MD5.Create())); 
// Create the other 4 strategies. 

broadcast.LinkTo(strategy1); 
broadcast.LinkTo(strategy2); 
// Link the other 4. 

using (var fs = File.Open(@"yourfile.txt", FileMode.Open, FileAccess.Read)) 
using (var br = new BinaryReader(fs)) 
{ 
    while (br.PeekChar() != -1) 
    { 
    broadcast.Post(br.ReadBytes(1024 * 16)); 
    } 
} 

El BroadcastBlock<T> se transmitirá cada trozo de datos a todos los ActionBlock<T> instancias vinculadas.

Dado que su pregunta se centró más en cómo lograr que esto ocurra al mismo tiempo, le dejaré la implementación de DoHash a usted.

private void DoHash(byte[] input, HashAlgorithm algorithm) 
{ 
    // You will need to implement this. 
} 
+0

Esto parece ser un enfoque muy interesante para el multihilo. Es una pena que esté en .net 4.5. Por alguna razón, me es bastante difícil convencerme de usar .net 4.0, ya que todavía no me parece lo suficientemente convencional. – agent154

+0

Parece que este enfoque no funcionará. Se llamará a DoHash para cada matriz de bytes de entrada. ¿Cómo deberían combinarse? – Petro

Cuestiones relacionadas