2009-01-30 64 views

Respuesta

39

El método que publicó no es particularmente bueno. Vamos a romper este aparte:

// new StreamReader("file.txt").ReadToEnd().Split(new char[] {'\n'}).Length 
//  becomes this: 
var file = new StreamReader("file.txt").ReadToEnd(); // big string 
var lines = file.Split(new char[] {'\n'});   // big array 
var count = lines.Count; 

En realidad estás sosteniendo este archivo en la memoria dos veces: una para leer todas las líneas, una vez que dividirlo en una matriz. El recolector de basura odia eso.

Si le gustan los forros uno, puede escribir System.IO.File.ReadAllLines(filePath).Length, pero eso aún recupera todo el archivo en una matriz. No tiene sentido hacer eso si no vas a sostener la matriz.

Una solución más rápida sería:

int TotalLines(string filePath) 
{ 
    using (StreamReader r = new StreamReader(filePath)) 
    { 
     int i = 0; 
     while (r.ReadLine() != null) { i++; } 
     return i; 
    } 
} 

El código anterior tiene (como máximo) una línea de texto en la memoria en cualquier momento dado. Va a ser eficiente siempre que las líneas sean relativamente cortas.

6

Pues bien, el problema de hacer esto es que se puede asignar una gran cantidad de la memoria cuando se hace esto en archivos grandes.

Preferiría leer el archivo línea por línea e incrementar manualmente un contador. Esto puede no ser de una sola línea, pero es mucho más eficiente con la memoria.

De forma alternativa, puede cargar los datos en fragmentos de tamaño uniforme y contar los saltos de línea en estos. Esta es probablemente la forma más rápida.

2

Sure - lee todo el flujo en la memoria. Es escueto, pero hoy puedo crear un archivo que fracasará tanto.

Lea un carácter a la vez e incremente su recuento en la nueva línea.

EDITAR - después de una investigación rápida Si desea terso y desea que el nuevo y brillante sensación genérica, considere esto:

public class StreamEnumerator : IEnumerable<char> 
{ 
    StreamReader _reader; 

    public StreamEnumerator(Stream stm) 
    { 
     if (stm == null) 
      throw new ArgumentNullException("stm"); 
     if (!stm.CanSeek) 
      throw new ArgumentException("stream must be seekable", "stm"); 
     if (!stm.CanRead) 
      throw new ArgumentException("stream must be readable", "stm"); 

     _reader = new StreamReader(stm); 
    } 

    public IEnumerator<char> GetEnumerator() 
    { 
     int c = 0; 
     while ((c = _reader.Read()) >= 0) 
     { 
      yield return (char)c; 
     } 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

que define una nueva clase que le permite enumerar sobre los arroyos, a continuación, el código de conteo puede tener este aspecto:

StreamEnumerator chars = new StreamEnumerator(stm); 
int lines = chars.Count(c => c == '\n'); 

que le da una buena expresión lambda escueta hacer (más o menos) lo que quiere.

todavía prefieren el Old School:

public static int CountLines(Stream stm) 
    { 
     StreamReader _reader = new StreamReader(stm); 
     int c = 0, count = 0; 
     while ((c = _reader.Read()) != -1) 
     { 
      if (c == '\n') 
      { 
       count++; 
      } 
     } 
     return count; 
    } 

NB: Versión Environment.NewLine deja como ejercicio para el lector

+0

Esto no funciona cuando se busca Environment.NewLine , que generalmente es una cadena de dos caracteres (CrLf). – spoulson

+0

Aunque tiene la idea correcta. Entonces, ¿qué hay de usar un RegEx para buscar instancias de Environment.NewLine? – JMD

-1

Suponiendo que el archivo existe y se puede abrir, que va a funcionar.

No es muy fácil de leer o segura ...

4

Si usted está buscando una solución a corto, puedo darle una sola línea que al menos le ahorra tener que dividir el resultado:

int i = File.ReadAllLines("file.txt").Count; 

Pero eso tiene los mismos problemas de leer un archivo grande en la memoria que su original. Realmente debería usar un lector de flujo y contar los saltos de línea a medida que los lee hasta que llegue al final del archivo.

+0

Olvidé poner los corchetes: int i = File.ReadAllLines ("file.txt"). Count(); –

0

¿Mayby esto?

string file = new StreamReader("YourFile.txt").ReadToEnd(); 
string[] lines = file.Split('\n'); 
int countOfLines = lines.GetLength(0)); 
Cuestiones relacionadas