Как быстро считать строки?
Я попробовал unxutils 'wc -l
, но он разбился для файлов объемом 1 ГБ. Я пробовал этот код С#
long count = 0;
using (StreamReader r = new StreamReader(f))
{
string line;
while ((line = r.ReadLine()) != null)
{
count++;
}
}
return count;
Он читает 500 МБ файл за 4 секунды
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);
}
Считывает через 10 секунд
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);
}
Занимает 7 секунд
Что-нибудь быстрее я еще не пробовал?
Ответы
Ответ 1
Ваш первый подход уже выглядит как оптимальное решение. Имейте в виду, что вы в основном не связаны с ЦП, но ограничены скоростью чтения HD, которая при 500 МБ /4 сек = 125 МБ/с уже довольно быстро. Единственный способ получить быстрее, чем через RAID или использование SSD, а не только с помощью лучшего алгоритма.
Ответ 2
File.ReadLines
был введен в .NET 4.0
var count = File.ReadLines(file).Count();
работает через 4 секунды, в то же время, что и первый фрагмент кода
Ответ 3
Вы просто ищете инструмент для подсчета строк в файле и эффективно? Если да, попробуйте MS LogParser
Что-то вроде ниже даст вам количество строк:
LogParser "SELECT count(*) FROM file" -i:TEXTLINE
Ответ 4
Если вы действительно хотите быстро, рассмотрите C-код.
Если это утилита командной строки, она будет быстрее, потому что ей не придется инициализировать CLR или .NET. И он не перераспределяет новую строку для каждой строки, считанной из файла, что, вероятно, экономит время на пропускную способность.
У меня нет файлов с 1g строк, поэтому я не могу сравнивать. вы можете попробовать, хотя:
/*
* 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);
}
}
Ответ 5
Я думаю, что ваш ответ выглядит хорошо. Единственное, что я хотел бы добавить, это играть с размером буфера. Я чувствую, что это может изменить производительность в зависимости от размера вашего буфера.
Пожалуйста, обратитесь к размеру буфера при настройке Оптимальный размер файла для хранения файлов
Ответ 6
Вы пробовали 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;
}
Просто скомпилируйте с помощью:
flex -Cf scanner.l
gcc -O -o lineCount.exe scanner.c
Он принимает вход на stdin и выводит количество строк.