Tengo que sincronizar archivos grandes en algunas máquinas. Los archivos pueden tener hasta 6 GB de tamaño. La sincronización se realizará manualmente cada pocas semanas. No puedo tomar en cuenta el nombre del 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 verificació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
¿Existe una forma mejor, más rápida, de obtener la suma de comprobación (tal vez con una mejor función hash)?
c#
.net
large-files
checksum
crono
fuente
fuente
Respuestas:
El problema aquí es que
SHA256Managed
lee 4096 bytes a la vez (heredaFileStream
y anulaRead(byte[], int, int)
para ver cuánto lee del flujo de archivos), que es un búfer demasiado pequeño para el disco IO.Para acelerar las cosas (2 minutos para hash de archivo de 2 GB en mi máquina con SHA256, 1 minuto para MD5) envoltura
FileStream
enBufferedStream
y configurar el tamaño de búfer de tamaño razonable (probé con tampón ~ 1 Mb):fuente
No realice una suma de comprobación de todo el archivo, cree sumas de comprobación cada 100 MB aproximadamente, de modo que cada archivo tenga una colección de sumas de comprobación.
Luego, al comparar sumas de verificación, puede dejar de comparar después de la primera suma de verificación diferente, salir temprano y evitar que procese todo el archivo.
Todavía tomará el tiempo completo para archivos idénticos.
fuente
Como señaló Anton Gogolev , FileStream lee 4096 bytes a la vez de forma predeterminada, pero puede especificar cualquier otro valor utilizando el constructor FileStream:
Tenga en cuenta que Brad Abrams de Microsoft escribió en 2004:
fuente
fuente
Invoque el puerto de Windows de md5sum.exe . Es aproximadamente dos veces más rápido que la implementación de .NET (al menos en mi máquina usando un archivo de 1.2 GB)
fuente
Ok, gracias a todos ustedes, déjenme terminar esto:
fuente
Hice pruebas con el tamaño del búfer, ejecuté este código
Y probé con un archivo de 29½ GB de tamaño, los resultados fueron
Estoy ejecutando una CPU i5 2500K, 12 GB de RAM y una unidad SSD OCZ Vertex 4 de 256 GB.
Entonces pensé, ¿qué pasa con un disco duro estándar de 2TB? Y los resultados fueron así
Por lo tanto, recomendaría sin búfer o un búfer de máximo 1 mill.
fuente
Estás haciendo algo mal (probablemente un búfer de lectura demasiado pequeño). En una máquina de edad indecente (Athlon 2x1800MP de 2002) que tiene DMA en el disco probablemente fuera de control (6.6M / s es muy lento cuando se hacen lecturas secuenciales):
Cree un archivo 1G con datos "aleatorios":
1m5.299s
1m58.832s
Esto también es extraño, md5 es consistentemente más lento que sha1 para mí (reran varias veces).
fuente
Sé que llego tarde a la fiesta pero realicé una prueba antes de implementar la solución.
Realicé la prueba contra la clase MD5 incorporada y también md5sum.exe . En mi caso, la clase incorporada tomó 13 segundos, donde md5sum.exe también alrededor de 16-18 segundos en cada ejecución.
fuente
Puede echar un vistazo a XxHash.Net ( https://github.com/wilhelmliao/xxHash.NET )
El algoritmo xxHash parece ser más rápido que todos los demás.
Algunos puntos de referencia en el sitio xxHash: https://github.com/Cyan4973/xxHash
PD: aún no lo he usado.
fuente