2012-07-26 108 views
6

Intenté dividir el archivo alrededor de 32GB usando el siguiente código pero obtuve el memory exception.Cómo dividir el archivo de texto grande (32 GB) usando C#

Por favor sugiérame que divida el archivo usando C#.

string[] splitFile = File.ReadAllLines(@"E:\\JKS\\ImportGenius\\0.txt"); 

int cycle = 1; 
int splitSize = Convert.ToInt32(txtNoOfLines.Text); 
var chunk = splitFile.Take(splitSize); 
var rem = splitFile.Skip(splitSize); 

while (chunk.Take(1).Count() > 0) 
{ 
    string filename = "file" + cycle.ToString() + ".txt"; 
    using (StreamWriter sw = new StreamWriter(filename)) 
    { 
     foreach (string line in chunk) 
     { 
    sw.WriteLine(line); 
     } 
    } 
    chunk = rem.Take(splitSize); 
    rem = rem.Skip(splitSize); 
    cycle++; 
} 
+6

Eso es fácil de arreglar. Simplemente compre más de 32 GB de RAM y podrá leer todo el archivo en la memoria. – Stilgar

+0

Supongo que necesitaría un StreamReader – V4Vendetta

+1

Acaba de leer todo el archivo de texto de 32 GB en la memoria a la vez, lo que no es ético. –

Respuesta

11

Bueno, para empezar necesita usar File.ReadLines (suponiendo que esté utilizando .NET 4) para que no intente leer todo en la memoria. Luego seguiría llamando a un método para escupir el "próximo", sin embargo, muchas líneas a un nuevo archivo:

int splitSize = Convert.ToInt32(txtNoOfLines.Text); 
using (var lineIterator = File.ReadLines(...).GetEnumerator()) 
{ 
    bool stillGoing = true; 
    for (int chunk = 0; stillGoing; chunk++) 
    { 
     stillGoing = WriteChunk(lineIterator, splitSize, chunk); 
    } 
} 

... 

private static bool WriteChunk(IEnumerator<string> lineIterator, 
           int splitSize, int chunk) 
{ 
    using (var writer = File.CreateText("file " + chunk + ".txt")) 
    { 
     for (int i = 0; i < splitSize; i++) 
     { 
      if (!lineIterator.MoveNext()) 
      { 
       return false; 
      } 
      writer.WriteLine(lineIterator.Current); 
     } 
    } 
    return true; 
} 
+0

Gracias por su respuesta Jon. – Jaffer

+0

Pero al intentar usar su código, muestra que para los iteradores "No se pudo encontrar la directiva o referencia de ensamblado". Por favor, ayúdame a rectificar este – Jaffer

+0

@Jaffer: Lo siento, error tipográfico - que debería haber sido 'IEnumerator '. Fijo. –

0

El problema aquí es que usted está leyendo el contenido de todo el archivo en la memoria a la vez con File.ReadAllLines(). Lo que debe hacer es abrir un FileStream con File.OpenRead() y leer/escribir fragmentos más pequeños.

Editar: En realidad para su caso ReadLine es obviamente mejor. Ver otras respuestas :)

0

Utilice un StreamReade r para leer el archivo, escriba con un StreamWriter.

6

No lea inmediatamente todas las líneas en una matriz, pero el uso StremReader.ReadLine método, como:

using (StreamReader sr = new StreamReader(@"E:\\JKS\\ImportGenius\\0.txt")) 
{ 
    while (sr.Peek() >= 0) 
    { 
     var fileLine = sr.ReadLine(); 
     //do something with line 
    } 
} 
+1

Para ser quisquilloso, una línea podría ser> 32 GB – Guillaume

+0

@Guillaume: Teniendo en cuenta que OP utiliza ReadAllLines I * supongo * el formato del archivo es ese que supongo que es, pero dividido por líneas, y no una sola línea grande. – Tigran

+0

y aceptamos que podría ser un problema si el archivo no proviene de un par confiable o si el formato no está bien definido. Además, copiar un archivo línea por línea es ineficiente. Reutilizar un buffer (digamos 32K) mejoraría mucho. Esto también podría ser un problema en archivos> 32 GB. Aún así, su solución podría ser suficiente para las necesidades de Jaffer. – Guillaume

3

En lugar de leer todo el archivo a la vez utilizando File.ReadAllLines, utilice File.ReadLines en un bucle foreach para leer el líneas según sea necesario.

foreach (var line in File.ReadLines(@"E:\\JKS\\ImportGenius\\0.txt")) 
{ 
    // Do something 
} 

Editar: En una nota relacionada, usted no tiene que escapar de sus barras invertidas cuando anteponiendo la cadena con una '@'. Por lo tanto, escriba "E:\\JKS\\ImportGenius\\0.txt" o @"E:\JKS\ImportGenius\0.txt", pero @"E:\\JKS\\ImportGenius\\0.txt" es redundante.

3
File.ReadAllLines 

que leerá el archivo entero en la memoria .

Para trabajar con archivos grandes, solo necesita leer lo que necesita ahora en la memoria, y luego tirarlo tan pronto como haya terminado con la misma.

Una mejor opción sería File.ReadLines que devuelve un enumerador vago, los datos solo se leen en la memoria a medida que obtiene la siguiente línea del enumerador. Siempre que evite enumeraciones múltiples (p. Ej., No use Count()), solo se leerán partes del archivo.

Cuestiones relacionadas