valores tres sume sumar suma que programar programa para números numeros lenguaje hacer datos como archivo c# .net large-files checksum
md5sum.exemd5sum.exe

tres - ¿Cuál es la forma más rápida de crear una suma de comprobación para archivos grandes en C#



suma de tres numeros en c (7)

Tengo que sincronizar archivos grandes en algunas máquinas. Los archivos pueden tener un tamaño de hasta 6GB. La sincronización se realizará manualmente cada pocas semanas. No puedo tomar en consideración el nombre de archivo porque pueden cambiar en cualquier momento.

Mi plan es crear sumas de verificación en la PC de destino y en la PC de origen y luego copiar todos los archivos con una suma de comprobación, que aún no están en el destino, al destino. Mi primer intento fue algo como esto:

using System.IO; using System.Security.Cryptography; private static string GetChecksum(string file) { using (FileStream stream = File.OpenRead(file)) { SHA256Managed sha = new SHA256Managed(); byte[] checksum = sha.ComputeHash(stream); return BitConverter.ToString(checksum).Replace("-", String.Empty); } }

El problema fue el tiempo de ejecución:
- con SHA256 con un archivo de 1,6 GB -> 20 minutos
- con MD5 con un archivo de 1,6 GB -> 6,15 minutos

¿Hay una forma mejor, más rápida, de obtener la suma de comprobación (quizás con una mejor función hash)?


Como señaló Anton Gogolev, FileStream lee 4096 bytes a la vez de manera predeterminada, pero puede especificar cualquier otro valor utilizando el constructor FileStream:

new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 16 * 1024 * 1024)

Tenga en cuenta que Brad Abrams de Microsoft escribió en 2004:

no hay beneficio de envolver un BufferedStream alrededor de un FileStream. Copiamos la lógica de almacenamiento en búfer de BufferedStream en FileStream hace aproximadamente 4 años para fomentar un mejor rendimiento predeterminado

source


El problema aquí es que SHA256Managed lee 4096 bytes a la vez (hereda de FileStream y reemplaza a Read(byte[], int, int) para ver cuánto lee de filestream), que es un búfer demasiado pequeño para el disco IO.

Para agilizar las cosas (2 minutos para el archivo hash de 2 Gb en mi máquina con SHA256, 1 minuto para MD5) ajuste FileStream en BufferedStream y configure un tamaño de búfer de tamaño razonable (lo intenté con ~ 1 MB de búfer):

// Not sure if BufferedStream should be wrapped in using block using(var stream = new BufferedStream(File.OpenRead(filePath), 1200000)) { // The rest remains the same }


Estás haciendo algo mal (probablemente sea un buffer de lectura demasiado pequeño). En una máquina de edad indefinida (Athlon 2x1800MP desde 2002) que tiene DMA en el disco probablemente fuera de control (6.6M / s es muy lento cuando hace lecturas secuenciales):

Crea un archivo 1G con datos "aleatorios":

# dd if=/dev/sdb of=temp.dat bs=1M count=1024 1073741824 bytes (1.1 GB) copied, 161.698 s, 6.6 MB/s # time sha1sum -b temp.dat abb88a0081f5db999d0701de2117d2cb21d192a2 *temp.dat

1m5.299s

# time md5sum -b temp.dat 9995e1c1a704f9c1eb6ca11e7ecb7276 *temp.dat

1m58.832s

Esto también es extraño, md5 es consistentemente más lento que sha1 para mí (reran varias veces).


Hice pruebas con tamaño de búfer, ejecutando este código

using (var stream = new BufferedStream(File.OpenRead(file), bufferSize)) { SHA256Managed sha = new SHA256Managed(); byte[] checksum = sha.ComputeHash(stream); return BitConverter.ToString(checksum).Replace("-", String.Empty).ToLower(); }

Y probé con un archivo de 29½ GB de tamaño, los resultados fueron

  • 10,000: 369,24s
  • 100,000: 362,55s
  • 1.000.000: 361,53s
  • 10,000,000: 434,15s
  • 100,000,000: 435,15s
  • 1.000.000.000: 434,31s
  • Y 376,22s cuando se usa el código original sin buffer.

Estoy ejecutando una CPU i5 2500K, 12 GB RAM y una unidad OCZ Vertex 4 256 GB SSD.

Entonces pensé, ¿qué tal un disco duro estándar de 2TB? Y los resultados fueron así

  • 10,000: 368,52s
  • 100,000: 364,15s
  • 1.000.000: 363,06s
  • 10,000,000: 678,96s
  • 100,000,000: 617,89s
  • 1.000.000.000: 626,86s
  • Y para ninguno amortiguado 368,24

Por lo tanto, recomendaría que no haya ningún buffer o un buffer de un máximo de 1 mill.


Invoca el puerto de md5sum.exe de md5sum.exe . Es aproximadamente dos veces más rápido que la implementación de .NET (al menos en mi máquina con un archivo de 1.2 GB)

public static string Md5SumByProcess(string file) { var p = new Process (); p.StartInfo.FileName = "md5sum.exe"; p.StartInfo.Arguments = file; p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.Start(); p.WaitForExit(); string output = p.StandardOutput.ReadToEnd(); return output.Split('' '')[0].Substring(1).ToUpper (); }


No haga suma de comprobación del archivo completo, cree sumas de comprobación cada 100mb o más, de modo que cada archivo tenga una colección de sumas de comprobación.

Luego, al comparar las sumas de comprobación, puede dejar de comparar después de la primera suma de comprobación diferente, salir temprano y evitar que procese el archivo completo.

Todavía tomará todo el tiempo para archivos idénticos.


Ok, gracias a todos ustedes, déjenme resumir esto:

  1. usar un exe "nativo" para hacer el hashing tomó un tiempo de 6 minutos a 10 segundos, lo cual es enorme.
  2. Aumentar el búfer fue incluso más rápido: el archivo de 1,6 GB tardó 5,2 segundos con MD5 en .Net, así que iré con esta solución, gracias de nuevo