2012-04-30 22 views
7

Tengo un archivo de 4 Gb que quiero buscar y reemplazar en un byte. He escrito un programa simple para hacerlo, pero lleva demasiado tiempo (90 minutos +) hacer un solo descubrimiento y reemplazarlo. Algunos editores hexadecimales que he probado pueden realizar la tarea en menos de 3 minutos y no cargan todo el archivo de destino en la memoria. ¿Alguien sabe un método donde puedo lograr lo mismo? Aquí está mi código actual:Procesando archivos enormes en C#

public int ReplaceBytes(string File, byte[] Find, byte[] Replace) 
    { 
     var Stream = new FileStream(File, FileMode.Open, FileAccess.ReadWrite); 
     int FindPoint = 0; 
     int Results = 0; 
     for (long i = 0; i < Stream.Length; i++) 
     { 
      if (Find[FindPoint] == Stream.ReadByte()) 
      { 
       FindPoint++; 
       if (FindPoint > Find.Length - 1) 
       { 
        Results++; 
        FindPoint = 0; 
        Stream.Seek(-Find.Length, SeekOrigin.Current); 
        Stream.Write(Replace, 0, Replace.Length); 
       } 
      } 
      else 
      { 
       FindPoint = 0; 
      } 
     } 
     Stream.Close(); 
     return Results; 
    } 

Buscar y reemplazar son relativamente pequeños en comparación con el "Archivo" de 4G por cierto. Puedo ver fácilmente por qué mi algoritmo es lento, pero no estoy seguro de cómo podría hacerlo mejor.

+8

Antes que nada, lea más de 1 byte a la vez. – SLaks

+0

http://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm – SLaks

Respuesta

3

Parte del problema puede ser que estás leyendo la transmisión de un byte a la vez. Intenta leer trozos más grandes y reemplazarlos. Empezaría con unos 8kb y luego probaría con algunos trozos más grandes o más pequeños para ver qué le ofrece el mejor rendimiento.

2

En lugar de leer bytes de archivos por byte leído por búfer:

buffer = new byte[bufferSize];    
currentPos = 0; 
length = (int)Stream .Length; 
while ((count = Stream.Read(buffer, currentPos, bufferSize)) > 0) 
{ 
    currentPos += count; 
    .... 
} 
+0

¡¡¡Buena respuesta !!! ThanX. – hsalimi

1

Otra forma más fácil de leer más de un byte a la vez:

var Stream = new BufferedStream(new FileStream(File, FileMode.Open, FileAccess.ReadWrite)); 

Combinando esto con el ejemplo de Saeed Amiri de cómo leer en un búfer, y uno de los mejores algoritmos de búsqueda/reemplazo binarios debería darle mejores resultados.

3

Hay un montón de mejores algoritmos para encontrar una subcadena en una cadena (que es básicamente lo que está haciendo)

comenzar aquí:

http://en.wikipedia.org/wiki/String_searching_algorithm

La esencia de ellos es que se puede omita una gran cantidad de bytes mediante el análisis de su subcadena. He aquí un ejemplo sencillo

4 GB de archivos comienza con: ABCDEFGHIJKLMNOP

Su subcadena es: NOP

  1. Se omite la longitud de la subcadena-1 y comprueba contra el último byte, por lo compare C a P
  2. No concuerda, por lo que la subcadena no es los primeros 3 bytes
  3. Además, C no está en la subcadena en todo, por lo que puede saltar más de 3 bytes (len de subcadena)
  4. Comparar F a P, no coincide, F no está en subcadena, saltar 3
  5. Compare I a P, etc, etc

Si coincide, retroceda. Si el carácter no coincide, pero está en la subcadena, entonces debe hacer una comparación más en ese punto (lea el enlace para más detalles)

1

Debería intentar usar memory-mapped files. C# los admite comenzando con la versión 4.0.

Un archivo mapeado en memoria contiene el contenido de un archivo en la memoria virtual.

Los archivos persistentes son archivos mapeados en memoria que están asociados con un archivo fuente en un disco. Cuando el último proceso ha terminado de trabajar con el archivo, los datos se guardan en el archivo fuente en el disco. Estos archivos mapeados en memoria son adecuados para trabajar con archivos fuente extremadamente grandes.

+0

cualquier buena muestra "real" con el código fuente completo? – Kiquenet

Cuestiones relacionadas