Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Посчитать строки в текстовике, используя стринговый метод 
:(
    Опции темы
Витаминка
Дата 27.12.2006, 06:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 56
Регистрация: 9.12.2006

Репутация: 1
Всего: 1



Привет! С праздником вас! smile  Как можно посчитать кол-во строк в txt файле, если я использую стринговый метод?

Это сообщение отредактировал(а) Витаминка - 27.12.2006, 06:08
PM MAIL   Вверх
aktuba
Дата 27.12.2006, 06:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Смышленный
***


Профиль
Группа: Завсегдатай
Сообщений: 1915
Регистрация: 24.4.2006
Где: Планета Земля

Репутация: 16
Всего: 38



Код

function GetStringsCount: Integer;
var
  lStr: TStringList;
begin
  lStr := TStringList.Create;
  try
    lStr.LoadFromFile(FileName);
    Result := lStr.Count;
  finally
    lStr.Free;
  end;
end;



--------------------
user posted image
PM MAIL WWW Skype   Вверх
Витаминка
Дата 27.12.2006, 07:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 56
Регистрация: 9.12.2006

Репутация: 1
Всего: 1



aktuba спасибки  smile 
PM MAIL   Вверх
ivan219
Дата 27.12.2006, 14:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1121
Регистрация: 19.11.2005
Где: Планета земля

Репутация: 2
Всего: 12



А что будет работать быстрее этот код или тот что выше smile 
Код

function f:Integer;
var
    TF: TextFile;
    S: String;
begin
 AssignFile(TF,'file.txt');
 Reset(TF);
 try
  while not Eof(TF) do
   begin
    Readln(TF,S);
    Inc(I);
   end;
 finally
  CloseFile(TF);
 end;
 Result:=I;
end;

PM MAIL ICQ   Вверх
Matematik
Дата 27.12.2006, 19:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1027
Регистрация: 11.3.2006

Репутация: 17
Всего: 50



ivan219, зависит от размера файла. Твой вариант вобщем-то "лучше", т.к. первый вариант (stringlist) загружает весь файл в память, там парсит на отдельные строки. 
Для небольших файлов и если не надо считать много файлов оба алгоритма "одинаковые".
PM MAIL WWW ICQ   Вверх
W4FhLF
Дата 27.12.2006, 19:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


found myself
****


Профиль
Группа: Участник Клуба
Сообщений: 2831
Регистрация: 2.12.2006

Репутация: 6
Всего: 121



Хотите скорость?smile Тада смотрите:

Код


Function GetStringCount(Path: pChar): dword;
var
hFile, hMap, fSize: dword;
pMemory: pointer;
begin
  hFile := CreateFile(Path, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0);
  fSize := GetFileSize(hFile,0);
  hMap := CreateFileMapping(hFile, nil, PAGE_READONLY, 0, 0, nil);
  pMemory := MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
  asm
    push eax
    push ecx
    push ebx
    mov eax,pMemory
    mov ecx,fSize
    dec ecx
    xor ebx,ebx
    @loop:
      cmp byte ptr[eax+ecx],$D
      jne @f
        inc ebx
      @f:
      dec ecx
      jne @loop
    inc ebx
    mov Result,ebx
    pop ebx
    pop ecx
    pop eax
  end;
  UnmapViewOfFile(pMemory);
  CloseHandle(hMap);
  CloseHandle(hFile);
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  GetStringCount('E:\Temp\english.txt');
end;



Кол-во строк в файле размером 33 мегабайта считается абсолютно моментально, т.е. даже незаметно, что происходит. Однако, если нужно работать с большими файлами(болше 80 метров), то лучше читать файл участками по 64 Кб и считать в каждом кол-во переносов, иначе для файловых проекций, который я использовал в примере, ваш своп раздует до ужасных размеровsmile

Это сообщение отредактировал(а) W4FhLF - 27.12.2006, 19:53


--------------------
"Бог умер" © Ницше
"Ницше умер" © Бог
PM ICQ   Вверх
ivan219
Дата 30.12.2006, 19:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1121
Регистрация: 19.11.2005
Где: Планета земля

Репутация: 2
Всего: 12



Да метод предложенный W4FhLF самый быстрый из 3 выше перечисленных.

Я поэксперементировал так фаил в котором 100000000 строк и размером 300000000 Байт.
Фаил такого типа:
Код

.
.
.
.
.

получается  100000000 точек

Время выполнения подщёта всего 1 Секунда smile на процесоре 2гГц и памяти 1Гб

Все остальные просто виснут smile 

Это сообщение отредактировал(а) ivan219 - 30.12.2006, 19:33
PM MAIL ICQ   Вверх
W4FhLF
Дата 31.12.2006, 07:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


found myself
****


Профиль
Группа: Участник Клуба
Сообщений: 2831
Регистрация: 2.12.2006

Репутация: 6
Всего: 121



Ассемблер всегда нужно использоват в подобных задачах. Я думаю мой вариант не самый удачный, ибо частые кеш-промахи из-за прыжка будут постоянно перегружать конвейер процессора. 


--------------------
"Бог умер" © Ницше
"Ницше умер" © Бог
PM ICQ   Вверх
Girder
Дата 1.1.2007, 13:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй 2
***


Профиль
Группа: Участник Клуба
Сообщений: 1993
Регистрация: 12.5.2004

Репутация: 31
Всего: 155



Цитата(ivan219 @  30.12.2006,  19:31 Найти цитируемый пост)
Все остальные просто виснут
Да что-ты?

Ловкость рук и ни какого ассемблера("на прямую"):
Код

Function GetStringCount(Path: pChar): dword;
var
hFile, hMap, fSize: dword;
pMemory,i: DWord;
begin
  hFile := CreateFile(Path, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0);
  fSize := GetFileSize(hFile,0);
  hMap := CreateFileMapping(hFile, nil, PAGE_READONLY, 0, 0, nil);
  pMemory := DWord(MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0));
 { asm
    push eax
    push ecx
    push ebx
    mov eax,pMemory
    mov ecx,fSize
    dec ecx
    xor ebx,ebx
    @loop:
      cmp byte ptr[eax+ecx],$D
      jne @f
        inc ebx
      @f:
      dec ecx
      jne @loop
    inc ebx
    mov Result,ebx
    pop ebx
    pop ecx
    pop eax
  end; }
  Result:=0;
  for i:=0 to fSize do
   if pByte(pMemory+i)^=$0a then inc(Result);
  UnmapViewOfFile(Pointer(pMemory));
  CloseHandle(hMap);
  CloseHandle(hFile);
end;


PS: Да и результат более точен smile


--------------------
Как слышим, так и пишим.
Истина где-то там...
PM   Вверх
TwisT_X
Дата 1.1.2007, 19:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


It's works!
**


Профиль
Группа: Участник
Сообщений: 293
Регистрация: 15.2.2005
Где: Earth

Репутация: нет
Всего: 4



А что если вот так вот без всяких там функций? 

Код

var MyText: Text;
      s1, Path: string;
      k: integer;

begin
     k:= 0;
     path:= 'c:\file.txt';
     assign(MyText, path);
     reset(MyText);
while not eof(Mytext) do
begin
        readln(MyText, s1);
        inc(k);
        writeln('# stroki ', k , s1);
end;





--------------------
Если ты упадешь я буду рядом. (с) Асфальт
PM MAIL WWW   Вверх
W4FhLF
Дата 1.1.2007, 20:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


found myself
****


Профиль
Группа: Участник Клуба
Сообщений: 2831
Регистрация: 2.12.2006

Репутация: 6
Всего: 121



Girder, 

Цитата

PS: Да и результат более точен


Ну убери inc ebx в конце, я на автомате поставил, суть-то не в этом.

Цитата

Ловкость рук и ни какого ассемблера("на прямую"):


И что это доказывает? То, что это можно было переписать на делфи понятно. Куски кода в которых очень критична скорость, я сначала пишу на ЯВУ, дизассемблирую, смотрю как оптимизировал это компилятор, если меня что-то не удовлетворяет я переписываю этот участок кода на ассемблер и сравниваю. В данном случае компилятор проиграл. 




--------------------
"Бог умер" © Ницше
"Ницше умер" © Бог
PM ICQ   Вверх
Girder
Дата 1.1.2007, 21:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй 2
***


Профиль
Группа: Участник Клуба
Сообщений: 1993
Регистрация: 12.5.2004

Репутация: 31
Всего: 155



Цитата(W4FhLF @  1.1.2007,  20:00 Найти цитируемый пост)
В данном случае компилятор проиграл.
Да что-ты? smile

PS: Как раз с точностью наоборот... приведенный тобой код работает медленнее по сравнению с кодом от компилятора.



--------------------
Как слышим, так и пишим.
Истина где-то там...
PM   Вверх
W4FhLF
Дата 2.1.2007, 09:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


found myself
****


Профиль
Группа: Участник Клуба
Сообщений: 2831
Регистрация: 2.12.2006

Репутация: 6
Всего: 121



Цитата

Да что-ты? 


Да я ничего. Я просто открыл дизасм и посмотрел на тело цикла. А ты что? Проигрыш там незначительный, порядка 5 тактов на иттерацию, но ведь это проигрыш, а я фанат ассемблера и даже не учитывая современную архитектуру и суперскалярность процессора, где эти 5 тактов могут быть незаметны, привык выжимать из алгоритма всё. 


--------------------
"Бог умер" © Ницше
"Ницше умер" © Бог
PM ICQ   Вверх
Girder
Дата 2.1.2007, 11:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй 2
***


Профиль
Группа: Участник Клуба
Сообщений: 1993
Регистрация: 12.5.2004

Репутация: 31
Всего: 155



Цитата(W4FhLF @  2.1.2007,  09:06 Найти цитируемый пост)
Да я ничего. Я просто открыл дизасм и посмотрел на тело цикла. А ты что? Проигрыш там незначительный, порядка 5 тактов на иттерацию, но ведь это проигрыш, а я фанат ассемблера и даже не учитывая современную архитектуру и суперскалярность процессора, где эти 5 тактов могут быть незаметны, привык выжимать из алгоритма всё.
А то... что! Приведенный тобой алгоритм хотя бы потому не рационален, потому что постоянно заставляет переключать разрядность команды(от компилятора таже вещь присутсвует, но тем не менее он более "оптимальным" получился)!

PS: И кстати... 0A - перевод строки; 0D- возврат каретки.

Ах... да! чуть не забыл... мало преимущество, а так smile 
Код

Function GetStringCount4(Path: pChar): dword;
var
hFile, hMap, fSize: dword;
pMemory: DWord;
i,j,n:DWord;
begin
  hFile := CreateFile(Path, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0);
  fSize := GetFileSize(hFile,0);
  hMap := CreateFileMapping(hFile, nil, PAGE_READONLY, 0, 0, nil);
  pMemory := DWord(MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0));
 { asm
    push eax
    push ecx
    push ebx
    mov eax,pMemory
    mov ecx,fSize
    dec ecx
    xor ebx,ebx
    @loop:
      cmp byte ptr[eax+ecx],$D
      jne @f
        inc ebx
      @f:
      dec ecx
      jne @loop
    inc ebx
    mov Result,ebx
    pop ebx
    pop ecx
    pop eax
  end; }
  Result:=0;
  j:=pMemory;
  for i:=0 to (fSize div 4) do
   begin
    n:=PDWord(j)^;
    if (n and $ff)=$0a then inc(Result);
    if (n and $ff00)=$0a00 then inc(Result);
    if (n and $ff0000)=$0a0000 then inc(Result);
    if (n and $ff000000)=$0a000000 then inc(Result);
    inc(PDWord(j));
   end;
  UnmapViewOfFile(pointer(pMemory));
  CloseHandle(hMap);
  CloseHandle(hFile);
end;


PS2: И не спрашивай... почему такой длинный код быстрее(на современных компах) - думай...! smile

Добавлено @ 11:42 
На смешанном файле размером 343912250, выигрыш на AMD64(3200+) порядка 20%  smile 


--------------------
Как слышим, так и пишим.
Истина где-то там...
PM   Вверх
W4FhLF
Дата 2.1.2007, 13:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


found myself
****


Профиль
Группа: Участник Клуба
Сообщений: 2831
Регистрация: 2.12.2006

Репутация: 6
Всего: 121



Цитата

А то... что! Приведенный тобой алгоритм хотя бы потому не рационален, потому что постоянно заставляет переключать разрядность команды(от компилятора таже вещь присутсвует, но тем не менее он более "оптимальным" получился)!


Ну только не надо говорить о рациональности по сравнению с твоим. Посмотри в дизассемблере, на одну иттерацию в твоём случае приходится два обращения к памяти и в общем случае используется 5 регистров, в моём случае обращение к памяти одно и используется 3 регистра. Поэтому в плане рациональности по сравнению с if pByte(pMemory+i)^=$0a then inc(Result); алгоритм на ассемблере удачнее. Хотя должен признать, что на практике, если не учитывать всех прочих факторов и измерить скорость с помощью GetTickCount, хотя это очень не тоно, но работают они одинаково быстро, твой алгоритм даже на 10% быстрее, но по бенчмаркам-то он проигрывает. smile  Ещё раз убеждаюсь в том, что архитектура современных процессоров настолько сложна, что невозможно прогнозировать скорость алгоритмов с такой точностью. Ну и кстати я не утверждал, что мой алгоритм не поддаётся дальнейшей оптимизации, наоборотsmile 
Небольшой проигрышь в скорости в данном случае, скорее всего, объясняется тем, что оба цикла имеют размер меньший 32-64 байта, а значит могут полностью поместиться в одной линейке кеш-памяти, доступ к которой, по скорости, на порядки выше, чем доступ к оперативной памяти. Далее, ты идёшь от начала участка к концу, но как известно при запросе однойго байта из ОЗУ берётся кол-во байт равное длине линейки кеша(в зависимости от процессора 32 или 64 байта), значит следующие 32-64 иттерации процессор оперативную память не трогает. Я же иду от конца к началу, вероятнее всего процессор не может предвидеть такие ситуации и гораздо чаще обращается к ОЗУ. 

Что ты подразумеваешь под разрядностью команды? У команды нет такого понятия "разрядность", есть размер смещения и размер непосредственного операнда и как это "переключать разрядность команды" я тоже не понимаю. Выразись точнее.

Поэтому признаю, что алгоритм мой более медленный, эх... smile

Цитата

PS: И кстати... 0A - перевод строки; 0D- возврат каретки.


Обижаешь! Я думал для программистов под win32 стало уже стандартом использовать эти два служебных символа вместе.

Цитата

Ах... да! чуть не забыл... мало преимущество, а так
...
PS2: И не спрашивай... почему такой длинный код быстрее(на современных компах) - думай...! 


А чего тут думать? Во-первых, если в файле кол-во строк, чья длина < 3 достаточно, то в одной иттерации можно определить сразу два(ну если без возврата каретки, то три) переноса. Во-вторых, считывается сразу машинное слово в регистр, на наших процессорах работа с DWORD'ами естественно происходит быстрее, чем с байтами и младшими частями регистров. В-третьих, сравнение происходит уже со значением регистра, а не со значением в памяти/кеше. Ну и конечно гораздо меньше кеш-промахов.

За этот алгоритм твёрдая 5+ и респектsmile





--------------------
"Бог умер" © Ницше
"Ницше умер" © Бог
PM ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0585 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.