¿Cuál es la forma más rápida de leer un archivo de texto línea por línea?

Resuelto Loren C Fortner asked hace 12 años • 9 respuestas

Quiero leer un archivo de texto línea por línea. Quería saber si lo estoy haciendo de la manera más eficiente posible dentro del alcance de .NET C#.

Esto es lo que estoy intentando hasta ahora:

var filestream = new System.IO.FileStream(textFilePath,
                                          System.IO.FileMode.Open,
                                          System.IO.FileAccess.Read,
                                          System.IO.FileShare.ReadWrite);
var file = new System.IO.StreamReader(filestream, System.Text.Encoding.UTF8, true, 128);

while ((lineOfText = file.ReadLine()) != null)
{
    //Do something with the lineOfText
}
Loren C Fortner avatar Nov 07 '11 20:11 Loren C Fortner
Aceptado

Para encontrar la forma más rápida de leer un archivo línea por línea, tendrás que realizar algunas evaluaciones comparativas. He realizado algunas pequeñas pruebas en mi computadora pero no puedes esperar que mis resultados se apliquen a tu entorno.

Usando StreamReader.ReadLine

Este es básicamente tu método. Por alguna razón, establece el tamaño del búfer en el valor más pequeño posible (128). Aumentar esto aumentará en general el rendimiento. El tamaño predeterminado es 1024 y otras buenas opciones son 512 (el tamaño del sector en Windows) o 4096 (el tamaño del clúster en NTFS). Tendrá que ejecutar una prueba comparativa para determinar el tamaño óptimo del búfer. Un búfer más grande es, si no más rápido, al menos no más lento que un búfer más pequeño.

const Int32 BufferSize = 128;
using (var fileStream = File.OpenRead(fileName))
  using (var streamReader = new StreamReader(fileStream, Encoding.UTF8, true, BufferSize)) {
    String line;
    while ((line = streamReader.ReadLine()) != null)
    {
      // Process line
    }
  }

El FileStreamconstructor le permite especificar FileOptions . Por ejemplo, si está leyendo un archivo grande secuencialmente de principio a fin, puede beneficiarse de FileOptions.SequentialScan. Una vez más, la evaluación comparativa es lo mejor que puedes hacer.

Usando File.ReadLines

Esto es muy parecido a su propia solución, excepto que se implementa utilizando un StreamReadertamaño de búfer fijo de 1024. En mi computadora, esto da como resultado un rendimiento ligeramente mejor en comparación con su código con un tamaño de búfer de 128. Sin embargo, puede obtener el mismo aumento de rendimiento utilizando un tamaño de búfer mayor. Este método se implementa mediante un bloque iterador y no consume memoria para todas las líneas.

var lines = File.ReadLines(fileName);
foreach (var line in lines)
  // Process line

Usando File.ReadAllLines

Esto es muy parecido al método anterior, excepto que este método genera una lista de cadenas utilizadas para crear la matriz de líneas devuelta, por lo que los requisitos de memoria son mayores. Sin embargo, regresa String[]y no IEnumerable<String>le permite acceder aleatoriamente a las líneas.

var lines = File.ReadAllLines(fileName);
for (var i = 0; i < lines.Length; i += 1) {
  var line = lines[i];
  // Process line
}

Usando String.Split

Este método es considerablemente más lento, al menos en archivos grandes (probado en un archivo de 511 KB), probablemente debido a cómo String.Splitestá implementado. También asigna una matriz para todas las líneas, lo que aumenta la memoria requerida en comparación con su solución.

using (var streamReader = File.OpenText(fileName)) {
  var lines = streamReader.ReadToEnd().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  foreach (var line in lines)
    // Process line
}

Mi sugerencia es usarlo File.ReadLinesporque es limpio y eficiente. Si necesita opciones especiales para compartir (por ejemplo, usa FileShare.ReadWrite), puede usar su propio código, pero debe aumentar el tamaño del búfer.

Martin Liversage avatar Nov 07 '2011 15:11 Martin Liversage

Si está utilizando .NET 4, simplemente utilice File.ReadLinesel que lo hace todo por usted. Sospecho que es muy parecido al tuyo, excepto que también puede usar FileOptions.SequentialScanun búfer más grande (128 parece muy pequeño).

Jon Skeet avatar Nov 07 '2011 13:11 Jon Skeet