2010-08-24 14 views
7

Tengo más de 125 archivos TSV de ~ 100Mb cada uno que deseo fusionar. La operación de fusión permite destruir los 125 archivos, pero no los datos. Lo que importa es que al final, termino con un gran archivo del contenido de todos los archivos uno después del otro (sin orden específico).Cómo fusionar eficientemente archivos gigantescos con C#

¿Hay una forma eficiente de hacerlo? Me preguntaba si Windows proporciona una API para simplemente hacer una gran "Unión" de todos esos archivos. De lo contrario, tendré que leer todos los archivos y escribir uno grande.

Gracias!

+0

PS: echar un vistazo aquí (posible duplicado): http://stackoverflow.com/questions/444309/what-would-be-the-fastest-way- para-concatenar-tres-archivos-en-c – Abel

Respuesta

17

Entonces, ¿"fusionar" es simplemente escribir los archivos uno después del otro? Eso es bastante sencillo: solo abra una secuencia de salida, y luego abra repetidamente una secuencia de entrada, copie los datos, cierre. Por ejemplo:

static void ConcatenateFiles(string outputFile, params string[] inputFiles) 
{ 
    using (Stream output = File.OpenWrite(outputFile)) 
    { 
     foreach (string inputFile in inputFiles) 
     { 
      using (Stream input = File.OpenRead(inputFile)) 
      { 
       input.CopyTo(output); 
      } 
     } 
    } 
} 

que está utilizando el método Stream.CopyTo que es nuevo en .NET 4. Si no está utilizando .NET 4, otro método de ayuda sería muy útil:

private static void CopyStream(Stream input, Stream output) 
{ 
    byte[] buffer = new byte[8192]; 
    int bytesRead; 
    while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0) 
    { 
     output.Write(buffer, 0, bytesRead); 
    } 
} 

No hay nada de lo que soy consciente es de que es más eficiente que esto ... pero, lo que es más importante, esto no ocupará mucha memoria en su sistema. No es como leer repetidamente todo el archivo en la memoria y luego escribir todo de nuevo.

EDITAR: Como se señaló en los comentarios, hay maneras en que puede jugar con las opciones de archivo potencialmente hacerlo un poco más eficiente en términos de lo que hace el sistema de archivos con los datos. Pero, fundamentalmente, vas a leer los datos y escribirlos, un búfer a la vez, en cualquier caso.

+0

Supongo que su respuesta a la pregunta es ¿no? –

+0

@Marcus: Supongo que sí ... aunque no estaba seguro de que el OP se hubiera sentido cómodo escribiendo las versiones de flujo anteriores. –

+0

¡Gracias Jon por la ayuda! :) No sabía sobre "CopyTo". – Martin

2

hacerlo desde la línea de comandos:

copy 1.txt+2.txt+3.txt combined.txt 

o

copy *.txt combined.txt 
+1

¿Te das cuenta de que dijo ** 125 ** archivos, ¿verdad? Eso va a ser muy largo y tedioso de escribir. Si le dio un programa C# para generar la cadena de copia, esa podría ser una respuesta * parcial *. – Aaronaught

+6

Amigo, luego use la segunda opción, con la máscara de archivo. O haga un comando dir (es decir, dir/b para obtener solo nombres de archivo), capture los nombres de archivo en un archivo y cree el comando en un buen editor de texto. Hay _muchas_ formas de evitar escribir 125 nombres de archivos. –

+0

El punto es que ni siquiera estuvo cerca de responder la pregunta. Has hecho un montón de suposiciones sobre el dominio del problema que posiblemente no puedas saber. Está bien * preguntar * para obtener más detalles sobre el dominio, pero no simplemente suponer que el autor de la pregunta ha elegido una forma incorrecta de resolver su problema. -1 para su solución posiblemente irrelevante y su tono argumentativo, "amigo". – Aaronaught

2

¿Quieres decir con fusión que desea decidir con cierta lógica personalizada lo pasan líneas ¿dónde? ¿O quieres decir que principalmente quieres concatenar los archivos en uno grande?

En el caso de este último, es posible que usted no necesita hacer esto mediante programación en absoluto, sólo generará un archivo por lotes con esto (/b es para binario, eliminar si no es necesario):

copy /b "file 1.tsv" + "file 2.tsv" "destination file.tsv" 

Usando C#, tomaría el siguiente enfoque. Escribir una función simple que copia dos corrientes:

void CopyStreamToStream(Stream dest, Stream src) 
{ 
    int bytesRead; 

    // experiment with the best buffer size, often 65536 is very performant 
    byte[] buffer = new byte[GOOD_BUFFER_SIZE]; 

    // copy everything 
    while((bytesRead = src.Read(buffer, 0, buffer.Length)) > 0) 
    { 
     dest.Write(buffer, 0, bytesRead); 
    } 
} 

// then use as follows (do in a loop, don't forget to use using-blocks) 
CopStreamtoStream(yourOutputStream, yourInputStream); 
+0

@Aaronaught: estaba a la mitad cuando me presenté, luego escribí la segunda parte. Pero también, tenga en cuenta la pequeña pista en el segundo párrafo: * "solo genera un archivo por lotes" *. Al generar, quiero decir: crear automáticamente. Pero luego decidí agregar el código C# :) – Abel

Cuestiones relacionadas