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 ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.