LINUX.ORG.RU
Не знаю, как в руби, но, думаю, он умеет открыть файл и пройтись курсором по нему от начала до конца с подсчетом символов переноса строки.
staseg ★★★★★
()
> Неужели лучше тупого считывания строчек в пустоту и счётчика ничего нет?

только libastral
lester ★★★★
()
Задал вопрос и сам же на него ответил. :-)

smh ★★★
()
irb(main):003:0> `wc -l vkontakte_passwords2.txt`.split.first.chomp.to_i
=> 292400
mholub
()
А есть предложения по поводу как прочитать количество строк не читая символы? Интересно :)
Deleted
()
Ответ на: комментарий от staseg
>открыть файл и пройтись курсором по нему от начала до конца с подсчетом символов переноса строки.

эээ.. лёгких путей не ищем. проще просто построчно читать файл в пустоту, как написал автор. другого вменяемого способа по-моему нет.

golodranez ★★★★
()
Ответ на: комментарий от golodranez
> другого вменяемого способа по-моему нет.

если файл большой и программа работает в основном с одними и теми же файлами, то можно где-нибудь хранить связку "путь" + "кол-во строк" + "дата последнего изменения", чтоб каждый раз не тратить время на подсчет
lester ★★★★
()
Ответ на: комментарий от golodranez
>эээ.. лёгких путей не ищем. проще просто построчно читать файл в пустоту, как написал автор. другого вменяемого способа по-моему нет.

Проще в каком плане? Писать меньше? Да. Хотя смотря на чем. Но пошустрее то будет пронестить курсором по файлу без таинственного "чтения в пустоту". Хотя это опять же зависит от языка наврное.

PS. Для руби может быть это и плохое решение, только название его знаю.

staseg ★★★★★
()
Ответ на: комментарий от staseg
>Но пошустрее то будет пронестить курсором по файлу без таинственного "чтения в пустоту".

Шустрее точно не будет. Да и короче ты не напишешь))

while(<FILEDESC>)
{
   i++;
};
golodranez ★★★★
()
Ответ на: комментарий от golodranez
>Шустрее точно не будет. Да и короче ты не напишешь))

Хм, возможно. Но я не зря писал (и оставлял себе лазейку;) ) про "смотря на чем писать". И топикстартер говорил про "руби и не только". В случае си (а может и си++, stl не знаю) будет шустрее и вероятно короче читать файл.

С другой стороны, если количество строк нужно узнать лишь любопытства ради, то нафик си. А если это практическая задача,.. На практике с такой не сталкивался, поэтому опять нафик сишное решение.

Но все же я предлагал это с мыслью, что решается некая задача на неком низкоуровневом языке, а в этих двух условиях, имхо это оптимально.

staseg ★★★★★
()
Ответ на: комментарий от staseg
>В случае си (а может и си++, stl не знаю) будет шустрее и вероятно короче читать файл.

НЕ БУДЕТ в случае Си короче читать файл посимвольно. Построчно всегда будет быстрее.

golodranez ★★★★
()
Ответ на: комментарий от golodranez
> НЕ БУДЕТ в случае Си короче читать файл посимвольно. Построчно всегда будет быстрее.

быстрее поблочно :)
lester ★★★★
()
Ответ на: комментарий от lester
>быстрее поблочно :)

Ты имеешь ввиду, что считать 1000 байт, поистать там конец строки, повторить до конца файла? Не, это полюбому медленней чем построчно.

golodranez ★★★★
()
Ответ на: комментарий от golodranez
> Ты имеешь ввиду, что считать 1000 байт, поистать там конец строки, повторить до конца файла? Не, это полюбому медленней чем построчно.

ну не 1000, минимум 4096, насчет полюбому - это почему?
lester ★★★★
()
Ответ на: комментарий от golodranez
Посчитал строки в /usr/src/linux/.config. Посимвольное считывание (fgetc) начисто слило построчному (getline) (под ним видимо выполняется поблочное чтение, как и сказал lester и до чего не додумался я).

Был не прав, исправлюсь.

staseg ★★★★★
()
Ответ на: комментарий от golodranez
>Ты имеешь ввиду, что считать 1000 байт, поистать там конец строки, повторить до конца файла? Не, это полюбому медленней чем построчно.

Т.е. при построчном чтении конец строки и не нужен вовсе?:)

staseg ★★★★★
()
Ответ на: комментарий от lester
>насчет полюбому - это почему?

ну смотри:
1) блочное, если я правильно понял
while(read(file, buf, 4096) > 0)
{
   for(i = 0; i < 4096; i++)
   {
      if(buf[i] == ´\n´)
          counter++;
   }
}

2) построчное
while(gets(file) != NULL)
  counter++;

С точки зрения алгоритма, по моему вопросов нет. второй вариант победил:)
golodranez ★★★★
()
Ответ на: комментарий от staseg
>Т.е. при построчном чтении конец строки и не нужен вовсе?:)

и вы получаете... [голосом якубовича] АВТОМОБиль :)

golodranez ★★★★
()
Ответ на: комментарий от golodranez
>и вы получаете... [голосом якубовича] АВТОМОБиль :)

И говорю о том, что функция, читающая файл построчно в любом случае у себя внутри ищет этот злополучный символ переноса. Но очевидно, ищет не непосредственно на винте (как я по наивности предполагал чуть раньше), а в заранее приготовленном буфере. Т.е. в итоге мы имеем поблочное чтение с поиском по блоку.

Вот только смысла писать велосипед нету. Короче говоря, благодарю за то, что подтолкнули размышления в верном направлении.

staseg ★★★★★
()
Ответ на: комментарий от lester
хотя у меня тут есть метровый файл с тестовыми данными - на нем и проверю
lester ★★★★
()
Ответ на: комментарий от staseg
>И говорю о том, что функция, читающая файл построчно в любом случае у себя внутри ищет этот злополучный символ переноса.

ага, а в посимвольном варианте кроме поиска конца строки ищется ещё и начало каждого блока.

golodranez ★★★★
()
файл 1.txt == 2.txt, кстати в варианте с fgets надо добавить проверку на длинные строки - тогда он станет еще медленней

Time 1: 12.938
Time 2: 4.781

	char buf[ 4096 ];
	clock_t start = clock();

	for( size_t k = 0 ; k < 1000 ; ++k )
	{
		FILE* file = fopen( "1.txt", "r" );
		if( file )
		{
			size_t counter = 0;
			// TODO: lines with length > 4096
			while( fgets( buf, 4096, file ) != NULL )
				counter++;

			fclose( file );
		}
	}

	clock_t end = clock();
	float interval = 1.0f * ( end - start ) / CLOCKS_PER_SEC;
	printf( "Time 1: %f\n", interval );

	start = clock();

	for( size_t k = 0 ; k < 1000 ; ++k )
	{
		FILE* file = fopen( "2.txt", "r" );
		if( file )
		{
			size_t counter = 0;
			size_t size = 0;
			while( size = fread( buf, 1, 4096, file ) )
			{
				for( size_t i = 0 ; i < size ; ++i )
				{
					if( buf[ i ] == '\n' )
						++counter;
				}
			}

			fclose( file );
		}
	}

	end = clock();
	interval = 1.0f * ( end - start ) / CLOCKS_PER_SEC;
	printf( "Time 2: %f\n", interval );

	getc( stdin );
lester ★★★★
()
Ответ на: комментарий от staseg
просто взял вариант от golodranez как есть, сейчас прогоню с getline
lester ★★★★
()
Ответ на: комментарий от staseg
как и ожидалось очееень медленно:

Time1: 62.157

	for( size_t k = 0 ; k < 1000 ; ++k )
	{
		size_t counter = 0;
		string str;

		ifstream file( "1.txt" );
		if( file.is_open() )
		{
			while( !file.eof() )
			{
				getline( file, str );
				++counter;
			}

			file.close();
		}
	}
lester ★★★★
()
Ответ на: комментарий от staseg
> Я про getline

это расширение gcc - потому им пользоваться не стоит, да и тут идет ненужное выделение памяти( которую надо еще и чистить ) + копирование, так что это самый медленный вариант
lester ★★★★
()
$ cat lor-3920508.c
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <memory.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <assert.h>

int main() {
        int fd, count = 0;
        off_t size;
        void *p, *e;

        assert((fd = open("/var/log/squid/access.log", O_RDONLY)) > -1);
        assert((size = lseek(fd, 0, SEEK_END)) > -1);
        assert(lseek(fd, 0, SEEK_SET) > -1);
        assert((p = mmap(NULL, (size_t)size, PROT_READ, MAP_PRIVATE, fd, 0)) != NULL);
        e = memrchr(p, '\n', size);
        if (e) do p = rawmemchr(p, '\n') + 1, ++count; while (p <= e);
        printf("%d\n", count);
        return 0;
}

$ gcc lor-3920508.c -o lor-3920508
$ time ./lor-3920508
802532

real    0m0.105s
user    0m0.080s
sys     0m0.023s

$ time wc -l /var/log/squid/access.log
802532 /var/log/squid/access.log

real    0m0.151s
user    0m0.083s
sys     0m0.057s

$ du -h /var/log/squid/access.log
107M    /var/log/squid/access.log
arsi ★★★★★
()
Ответ на: комментарий от staseg
> Влететь в своп, и... пускай весь мир подождет.

ЩИТО? Сдается мне, что кому то надо подучить матчасть.

baverman ★★★
()
Ответ на: комментарий от imp
хорошее решение, но:

1. только для ...nix
2. отлично подходит для скриптов, но за такое в С-ом коде надо руки обрывать( тем более, что "ручной" подсчет занимает несколько строк )
lester ★★★★
()
Ответ на: комментарий от baverman
> +1 Вот это дотошность!

LOL, тут два варианта:

1. нет NDEBUG и нас ждет вылет даже в релизе при любом чихе из-за abort
2. есть NDEBUG и код вообще не скомпилится
lester ★★★★
()
Ответ на: комментарий от lester
> 1. нет NDEBUG и нас ждет вылет даже в релизе при любом чихе из-за abort

/me lold. «релизе»… несомненно, это же я в реп коммитил, а не предлагал алгоритм подсчёта, попутно указав места с «shit happens»…

> 2. есть NDEBUG и код вообще не скомпилится

у вас кривая сборка libastral, срочно обновитесь! :)

arsi ★★★★★
()
Ответ на: комментарий от arsi
> /me lold. «релизе»… несомненно, это же я в реп коммитил, а не предлагал алгоритм подсчёта, попутно указав места с «shit happens»…

и ассерты поставили имеено по этой же причине, угу

> у вас кривая сборка libastral, срочно обновитесь! :)


открою вам секрет, если вы посмотрите объявление макроса assert, то вы удивитесь, но оно у вас будет таким:

#ifdef NDEBUG
#define assert(_Expression) ((void)0)
#else

и ваш пример таки соберется( благодаря тому, что у вас паскалевская? привычка описывать переменные в начале ), но четыре строки полностью "выпадут" из программы,
lester ★★★★
()
Ответ на: комментарий от lester
> и ассерты поставили имеено по этой же причине, угу

а вы таки заподозрили там другие мотивы? типа заговора против лора и т.п.? лол же.

> открою вам секрет […]

спасибо, кэп, что бы я без вас делал.

> и ваш пример таки соберется

ну у как оно с новым либастралом? удобнее, правда?

> у вас паскалевская? привычка описывать переменные в начале

ЩИТО? в С переменные уже можно описывать в конце? или с -lastral их можно вообще не описывать?

arsi ★★★★★
()
Ответ на: комментарий от arsi
> ну у как оно с новым либастралом? удобнее, правда?

уж лучше чем с кривыми руками ;)

> ЩИТО? в С переменные уже можно описывать в конце?


не поверите - их можно описывать где угодно
lester ★★★★
()
Ответ на: комментарий от lester
> не поверите - их можно описывать где угодно

хм, действительно, в с99 ввели… но я как-то по-старинке, тем более, что не все тулзы этот стандарт поддерживают.

arsi ★★★★★
()
Ответ на: комментарий от lester
>Time 1: 12.938 >Time 2: 4.781

Хммм... только что протестил твой бенчмарк:

Time 1: 34.180000 Time 2: 72.650002

файлы по 10 мегабайт. Код не менял. Результаты у нас диаметрально противоположные.

Система CentOS 5.2, ядро 2.6.18

golodranez ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.