Pregunta

¿Existe una manera fácil de determinar mediante programación el número de líneas dentro de un archivo de texto?

¿Fue útil?

Solución

Edición realmente tardía:Si está utilizando .NET 4.0 o posterior

El File la clase tiene una nueva ReadLines método que enumera líneas perezosamente en lugar de leerlas todas con avidez en una matriz como ReadAllLines.Así que ahora puedes tener eficiencia y concisión con:

var lineCount = File.ReadLines(@"C:\file.txt").Count();

Respuesta original

Si no le preocupa demasiado la eficiencia, simplemente puede escribir:

var lineCount = File.ReadAllLines(@"C:\file.txt").Length;

Para un método más eficiente, puedes hacer:

var lineCount = 0;
using (var reader = File.OpenText(@"C:\file.txt"))
{
    while (reader.ReadLine() != null)
    {
        lineCount++;
    }
}

Editar:En respuesta a preguntas sobre eficiencia.

La razón por la que dije que el segundo era más eficiente fue por el uso de la memoria, no necesariamente por la velocidad.El primero carga todo el contenido del archivo en una matriz, lo que significa que debe asignar al menos tanta memoria como el tamaño del archivo.El segundo simplemente recorre una línea a la vez, por lo que nunca tiene que asignar más de una línea de memoria a la vez.Esto no es tan importante para archivos pequeños, pero para archivos más grandes podría ser un problema (si intenta encontrar el número de líneas en un archivo de 4 GB en un sistema de 32 bits, por ejemplo, donde simplemente no hay suficiente espacio de direcciones en modo usuario para asignar una matriz de este tamaño).

En términos de velocidad, no esperaría que hubiera mucho.Es posible que ReadAllLines tenga algunas optimizaciones internas, pero, por otro lado, es posible que deba asignar una gran cantidad de memoria.Supongo que ReadAllLines podría ser más rápido para archivos pequeños, pero significativamente más lento para archivos grandes;aunque la única forma de saberlo sería medirlo con un cronómetro o un perfilador de código.

Otros consejos

Lo más fácil:

int lines = File.ReadAllLines("myfile").Length;

Esto usaría menos memoria, pero probablemente llevaría más tiempo.

int count = 0;
string line;
TextReader reader = new StreamReader("file.txt");
while ((line = reader.ReadLine()) != null)
{
  count++;
}
reader.Close();

¿Si por fácil te refieres a líneas de código que son fáciles de descifrar pero que tal vez sean ineficientes?

string[] lines = System.IO.File.RealAllLines($filename);
int cnt = lines.Count();

Probablemente esa sea la forma más rápida de saber cuántas líneas.

También puedes hacerlo (dependiendo de si lo estás almacenando en el búfer)

#for large files
while (...reads into buffer){
string[] lines = Regex.Split(buffer,System.Enviorment.NewLine);
}

Hay muchas otras formas, pero probablemente una de las anteriores sea la que elijas.

Puede leerlo rápidamente e incrementar un contador, simplemente use un bucle para incrementar, sin hacer nada con el texto.

cuente los retornos de carro/avances de línea.Creo que en Unicode siguen siendo 0x000D y 0x000A respectivamente.de esa manera puedes ser tan eficiente o ineficiente como quieras, y decidir si tienes que lidiar con ambos personajes o no.

Una opción viable, y que yo he usado personalmente, sería agregar su propio encabezado a la primera línea del archivo.Hice esto para un formato de modelo personalizado para mi juego.Básicamente, tengo una herramienta que optimiza mis archivos .obj, eliminando la basura que no necesito, los convierte a un mejor diseño y luego escribe el número total de líneas, caras, normales, vértices y UV de textura en la primera línea.Luego, esos datos son utilizados por varios buffers de matriz cuando se carga el modelo.

Esto también es útil porque solo necesita recorrer el archivo una vez para cargarlo, en lugar de una vez para contar las líneas, y nuevamente para leer los datos en los buffers creados.

Leer un archivo por sí solo lleva algo de tiempo, la recolección de basura del resultado es otro problema, ya que lee el archivo completo solo para contar los caracteres de nueva línea.

En algún momento, alguien tendrá que leer los caracteres del archivo, sin importar si este es el marco o si es su código.Esto significa que debe abrir el archivo y leerlo en la memoria. Si el archivo es grande, esto podría ser un problema ya que es necesario recolectar basura de la memoria.

Nima Ara hizo un buen análisis que quizás tengas en cuenta

Aquí está la solución propuesta, ya que lee 4 caracteres a la vez, cuenta el carácter de avance de línea y reutiliza la misma dirección de memoria nuevamente para la siguiente comparación de caracteres.

private const char CR = '\r';  
private const char LF = '\n';  
private const char NULL = (char)0;

public static long CountLinesMaybe(Stream stream)  
{
    Ensure.NotNull(stream, nameof(stream));

    var lineCount = 0L;

    var byteBuffer = new byte[1024 * 1024];
    const int BytesAtTheTime = 4;
    var detectedEOL = NULL;
    var currentChar = NULL;

    int bytesRead;
    while ((bytesRead = stream.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
    {
        var i = 0;
        for (; i <= bytesRead - BytesAtTheTime; i += BytesAtTheTime)
        {
            currentChar = (char)byteBuffer[i];

            if (detectedEOL != NULL)
            {
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 1];
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 2];
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 3];
                if (currentChar == detectedEOL) { lineCount++; }
            }
            else
            {
                if (currentChar == LF || currentChar == CR)
                {
                    detectedEOL = currentChar;
                    lineCount++;
                }
                i -= BytesAtTheTime - 1;
            }
        }

        for (; i < bytesRead; i++)
        {
            currentChar = (char)byteBuffer[i];

            if (detectedEOL != NULL)
            {
                if (currentChar == detectedEOL) { lineCount++; }
            }
            else
            {
                if (currentChar == LF || currentChar == CR)
                {
                    detectedEOL = currentChar;
                    lineCount++;
                }
            }
        }
    }

    if (currentChar != LF && currentChar != CR && currentChar != NULL)
    {
        lineCount++;
    }
    return lineCount;
}

Arriba puede ver que el marco subyacente también lee una línea un carácter a la vez, ya que necesita leer todos los caracteres para ver el avance de línea.

Si lo perfila como hecho en Bay Nima, verá que esta es una forma bastante rápida y eficiente de hacerlo.

try {
    string path = args[0];
    FileStream fh = new FileStream(path, FileMode.Open, FileAccess.Read);
    int i;
    string s = "";
    while ((i = fh.ReadByte()) != -1)
        s = s + (char)i;

    //its for reading number of paragraphs
    int count = 0;
    for (int j = 0; j < s.Length - 1; j++) {
            if (s.Substring(j, 1) == "\n")
                count++;
    }

    Console.WriteLine("The total searches were :" + count);

    fh.Close();

} catch(Exception ex) {
    Console.WriteLine(ex.Message);
}         

Puedes iniciar el "WC.exe" ejecutable (viene con UnixUtils y no necesita instalación) se ejecuta como un proceso externo.Admite diferentes métodos de recuento de líneas (como Unix, Mac y Windows).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top