¿Cómo contar líneas rápido?


He intentado unxutils' wc -l pero se estrelló para los archivos de 1 GB. Probé este código C #

long count = 0;
using (StreamReader r = new StreamReader(f))
{
    string line;
    while ((line = r.ReadLine()) != null)
    {
        count++;
    }
}

return count;

Lee un archivo de 500MB en 4 segundos

var size = 256;
var bytes = new byte[size];
var count = 0;
byte query = Convert.ToByte('\n');
using (var stream = File.OpenRead(file))
{
    int many;
    do
    {
        many = stream.Read(bytes, 0, size);
        count += bytes.Where(a => a == query).Count();                    
    } while (many == size);
}

Se lee en 10 segundos

var count = 0;
int query = (int)Convert.ToByte('\n');
using (var stream = File.OpenRead(file))
{
    int current;
    do
    {
        current = stream.ReadByte();
        if (current == query)
        {
            count++;
            continue;
        }
    } while (current!= -1);
}

Toma 7 segundos

¿Hay algo más rápido que no haya probado todavía?

Author: Jader Dias, 2011-05-23

6 answers

Su primer enfoque ya parece la solución óptima. Tenga en cuenta que en su mayoría no está limitado por la CPU, sino limitado por la velocidad de lectura del HD, que a 500MB / 4seg = 125MB/s ya es bastante rápido. La única manera de ser más rápido que eso es a través de RAID o utilizando SSD, no tanto a través de un algoritmo mejor.

 12
Author: SirViver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-23 18:46:33

File.ReadLines se introdujo en. NET 4.0

var count = File.ReadLines(file).Count();

Funciona en 4 segundos, al mismo tiempo que el primer fragmento de código

 11
Author: Jader Dias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-23 18:45:29

¿Está buscando una herramienta para contar líneas en un archivo, y de manera eficiente? Si es así, intente MS LogParser

Algo como a continuación le dará el número de líneas:

LogParser "SELECT count(*) FROM file" -i:TEXTLINE
 2
Author: manojlds,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-23 18:49:18

Si realmente quieres rápido, considera el código C.

Si se trata de una utilidad de línea de comandos, será más rápido porque no tendrá que inicializar el CLR o .NET. Y, no reasignará una nueva cadena para cada línea leída del archivo, lo que probablemente ahorra tiempo en el rendimiento.

No tengo ningún archivo con líneas 1g, así que no puedo comparar. puedes probar, sin embargo:

/*
 * LineCount.c
 *
 * count lines...
 *
 * compile with: 
 *
 *  c:\vc10\bin\cl.exe /O2 -Ic:\vc10\Include -I\winsdk\Include 
 *          LineCount.c -link /debug /SUBSYSTEM:CONSOLE /LIBPATH:c:\vc10\Lib
 *          /LIBPATH:\winsdk\Lib /out:LineCount.exe
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


void Usage(char *appname)
{
    printf("\nLineCount.exe\n");
    printf("  count lines in a text file...\n\n");
    printf("usage:\n");
    printf("  %s <filename>\n\n", appname);
}



int linecnt(char *file)
{
    int sz = 2048;
    char *buf = (char *) malloc(sz);
    FILE *fp = NULL;
    int n= 0;
    errno_t rc = fopen_s(&fp, file, "r");

    if (rc) {
        fprintf(stderr, "%s: fopen(%s) failed: ecode(%d)\n",
                __FILE__, file, rc);
        return -1;
    }

    while (fgets(buf, sz, fp)){
        int r = strlen(buf);
        if (buf[r-1] == '\n')
            n++;
        // could re-alloc here to handle larger lines
    }
    fclose(fp);
    return n;
}

int main(int argc, char **argv)
{
    if (argc==2) {
        int n = linecnt (argv[1]);
        printf("Lines: %d\n", n);
    }
    else {
        Usage(argv[0]);
        exit(1);
    }
}
 2
Author: Cheeso,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-23 18:57:55

Creo que tu respuesta se ve bien. Lo único que añadiría es jugar con el tamaño del búfer. Siento que puede cambiar el rendimiento dependiendo del tamaño de su búfer.

Por favor refiérase a buffer size at - Optimum file buffer read size?

 1
Author: istudy0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:46:54

¿Has probado flex?

%{
long num_lines = 0;
%}
%option 8bit outfile="scanner.c"
%option nounput nomain noyywrap
%option warn

%%
.+ { }
\n { ++num_lines; }
%%
int main(int argc, char **argv);

int main (argc,argv)
int argc;
char **argv;
{
yylex();
printf( "# of lines = %d\n", num_lines );
return 0;
}

Solo compila con:

flex -Cf scanner.l 
gcc -O -o lineCount.exe scanner.c

Acepta entrada en stdin y muestra el número de líneas.

 1
Author: Spencer Rathbun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-23 18:58:21