2010-01-29 54 views
7

¿Cuál es la forma más fácil de averiguar si dos archivos de texto son diferentes mediante programación? Dados dos archivos, solo necesito saber si son diferentes o no. Esto es para una herramienta rápida para ayudar con una fusión especialmente desagradable (cambio de idiomas de VB a C# en una rama (¡yay!) Y se hicieron muchos cambios en la otra), no entrará en producción.¿Cuál es la forma más fácil de averiguar si dos archivos son diferentes por programación?

soluciones posibles:

  1. Hash ambos archivos y comparar el hash
  2. los ficheros a y sólo hacer una cadena comparar
  3. llamada a una herramienta externa de diferenciar (por desgracia no tiene Winmerge una CLI para esto)

Si es posible, ignorar el espacio en blanco sería increíble, pero eso no me importa demasiado. Lo principal es que debe ser rápido y fácil.

Estoy usando .Net 3.5sp1 por cierto. Gracias por cualquier idea o punteros.

+0

http://unxutils.sourceforge.net/ tiene gnu diff para windows. 'diff -q archivo1 archivo2' es la sintaxis que desea – KitsuneYMG

+0

FWIW, una herramienta de tres vías le ayudará mostrando las diferencias entre los dos archivos VB mientras los compara con el nuevo archivo C#. Beyond Compare 3 PRO (BC3 PRO) y Araxis Merge tienen una comparación de 3 vías y se fusionan. BC3 Pro cuesta solo $ 50 y es una de las mejores herramientas de programación que usará para lidiar con fusiones y diferencias interactivas. – Adisak

Respuesta

11

Hay un artículo en Microsoft Knowledge Base, espero que ayude. Comparan los bytes para ver si dos archivos son diferentes - How to create a File-Compare function in Visual C#

+0

Ese enlace de KB está muerto, encontré un archivo aquí: http://www.java2s.com/Code/CSharp/File-Stream/Comparesthecontentof2files.htm –

10

La forma más rápida de hacerlo es comparar byte a byte de los archivos cargados en una secuencia. Hashing ambos archivos tomará demasiado tiempo para archivos de gran tamaño, comparar cadenas también, herramientas externas también.

La comparación de byte a byte será lo mejor para usted, ya que solo alcanzará el EOF de los archivos cuando ambos sean idénticos.

Si realiza una comparación de hash, una comparación de cadenas o herramientas externas, tendrá que recorrer todos los archivos todo el tiempo que compare, al comparar byte a byte solo lo hará en caso de que sean idénticos.

+1

+1: simple, eficiente, 100% correcto y claramente el más rápido – chburd

+3

Técnicamente no es el más rápido. El más rápido consiste en verificar los tamaños de archivo primero para el rechazo trivial. Además, la cantidad de tiempo para calcular un hash simple puede ser mínima en comparación con el tiempo de IO: primero asegúrese de realizar un almacenamiento en caché de archivos con lecturas de archivos de un tamaño decente. Además, la comparación de hash no tiene que analizar todo el archivo para rechazar: puede dividir los datos y simplemente comparar fragmentos de hash. Chunk hash cmp utilizando la recuperación previa de la memoria caché del procesador puede ser 2-3 veces más rápido que una comparación de byte ingenua (pero probablemente no será tan rápido como SIMD/SIAR cmp w/prefetching). Además, puedes hacer hash multithread o cmp fácilmente. – Adisak

3

¿Utilizaría un algoritmo Hash MD5 para comparar los resultados? Aquí hay un example.

+0

+1 Implementé esta solución. Funciona muy bien todo el tiempo. –

+1

Sí, excelentes resultados, mal rendimiento, intente comparar 2 archivos con 100MB cada uno, llevará mucho tiempo, no importa cuán diferentes sean los archivos, hacer byte a byte detendrá todo el proceso en los primeros byte encuentra. – Tufo

+0

+1 @Tufo - buen punto. –

0

partir de la pregunta - más fácil & Texto archivo

StreamReader sr1 = new StreamReader(filePath1); 
StreamReader sr2 = new StreamReader(filePath2); 
if (sr1.ReadToEnd() == sr2.ReadToEnd()) 
{ do stuff } 

No es rápido o bonito, pero es fácil

4

Comprobar byte a byte, aquí hay algo de código:

public static bool AreFilesIdentical(string path1, string path2) 
{ 
    using (FileStream file1 = new FileStream(path1)) { 
     using (FileStream file2 = new FileStream(path2)) { 

      if (file1.Length == file2.Length) { 
       while (file1.Position < file1.Length) { 
        if (file1.ReadByte() != file2.ReadByte()) { 
         return false; 
        } 
       } 
       return true; 
      } 
      return false; 
     } 
    } 

} 
+0

Sugiero decorar el FileStream con una secuencia de almacenamiento en búfer, o leer la corriente por bloques. –

+0

Parece que FileStream ya está almacenado en el búfer, http://blogs.msdn.com/b/brada/archive/2004/04/15/114329.aspx, por lo que no creo que ningún ajuste sea útil. – derkyjadex

0
if ($file1 != $file2) return true; 

Por supuesto, esto varía entre VB y C#

1

También depende de lo que está tratando de resolver. ¿Estás tratando de responder la pregunta: en este directorio de N archivos, encuentra todos los duplicados exactos? ¿O estos dos archivos son exactamente iguales?

Si está comparando específicamente dos archivos, el uso de byte por byte es más eficiente.

Pero si está tratando de encontrar todos los pares duplicados en N archivos, entonces un hash MD5 es mejor, porque puede crear y almacenar el valor hash MD5 una vez y comparar este valor mucho menor para cada par de archivos.De otro modo, estaría iterando sobre cada flujo de bytes de archivos para cada otro archivo en el directorio.

1

Implementé una versión muy especializada de diff hace un año (tenía archivos de más de 6GB y tuve que compararlos luego). Así que sé el funcionamiento interno de diff (lote de copia & pegar, por supuesto). Algunos pensamientos:

  • Si desea saber si son diferentes, compárelos byte por byte. Optimice comprobando si sus tamaños (longitudes) son diferentes y luego lea los archivos un byte a la vez y verifique si son diferentes. No tiene que preocuparse por el almacenamiento en búfer, ya que su API de archivos debería hacer eso por usted (.Net lo hace).
  • Si hay algunas reglas que desea aplicar al comparar:
    • Si va a ignorar espacios en blanco o cualquier otro carácter, a medida que lee el byte, comprueba si se deben ignorar. Si debería, lea el siguiente, pero solo en ese archivo.
    • Si hay reglas que se aplicarán en línea, luego lea el archivo línea por línea. Luego, haga la línea, ignorando lo que quiera ignorar.
    • Recuerde que la línea se puede definir como registro de longitud variable con una nueva línea como terminador (separador). Entonces puede definir la línea para que sea lo que quiera y leer exactamente eso, hash it y comparar.

puedo contribuir con código si lo desea. Diff'ing files es más complejo, porque también dará salida a lo diferente.

Cuestiones relacionadas