Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.02.20;
Скачать: CL | DM;

Вниз

Распарсить большой текстовый файл   Найти похожие ветки 

 
Brenagwynn   (2005-02-04 13:56) [0]

Есть текстовый файл приличных размеров (минимум порядка 50000 строк), представляющий собой таблицу (с известными разделителями и известным кол-вом столбцов). Может коллективный разум подкинет какой-нить алгоритм, или хотя бы идею, как его побыстрее распарсить? Понятно, что можно тупо построчно парсить (загрузив в стринглист, например), но может вдруг найдется что-нить получше...


 
wl ©   (2005-02-04 14:04) [1]

1.Создать объект excel В памяти и прочитать в него файлик.
2.должен быть провайдер базы данных для баз в виде таблиц в txt файле - но это всё имхо, сам ничего подобного не делал, только парсил построчно.


 
TUser ©   (2005-02-04 14:07) [2]

Я такую штуку через StringList делал. Очень не факт, что другие способы будут быстрее, особенно тот, который через TDataSet.


 
esu ©   (2005-02-04 14:10) [3]


> Brenagwynn   (04.02.05 13:56)  

Перегнать в excelе в какой-то более удобный формат для базы и дальше уже работать как с таблицей...


 
Александр Иванов ©   (2005-02-04 14:13) [4]

Для увеличения скорости я бы считывал все в одну строку, причем за раз, а ее бы парсил. Если текст больше 2 Гб, то сначала 2Гб, потом остаток последней строки + остаток из файла, и т.д.


 
Brenagwynn   (2005-02-04 14:15) [5]

Перегон в excel - идея хорошая, но увы, не катит (в тех условиях, в которых я нахожусь). А вот насчет провайдера - эт надо попробовать и сравнить. Может и не медленнее будет.


 
Brenagwynn   (2005-02-04 14:18) [6]


> Александр Иванов ©   (04.02.05 14:13) [4]
> Для увеличения скорости я бы считывал все в одну строку,
> причем за раз, а ее бы парсил. Если текст больше 2 Гб, то
> сначала 2Гб, потом остаток последней строки + остаток из
> файла, и т.д.

Мнэээ... А собсно почему это будет быстрее, чем загрузка в тот же стринглист и построчное парсение? Можно, конечно, и так попробовать... А файл там будет не 2 Гб (где-то порядка 3-5 Мб).


 
Александр Иванов ©   (2005-02-04 14:20) [7]

Brenagwynn   (04.02.05 14:18) [6]
(где-то порядка 3-5 Мб).

Тем более.


 
esu ©   (2005-02-04 14:21) [8]


> Brenagwynn   (04.02.05 14:15) [5]

А почему ты не хочешь загнать ее в таблицу ? Что там за условия такие, религия не позволяет ? :)


 
Александр Иванов ©   (2005-02-04 14:22) [9]

esu ©   (04.02.05 14:21) [8]
Изначально в вопросе говорилось о скорости, а Эксель - очень не идеальный вариант.


 
stone ©   (2005-02-04 14:25) [10]


>  Понятно, что можно тупо построчно парсить (загрузив в стринглист,
> например), но может вдруг найдется что-нить получше...

AssignFile + Readln + F1


 
Brenagwynn   (2005-02-04 14:25) [11]


> А почему ты не хочешь загнать ее в таблицу ? Что там за
> условия такие, религия не позволяет ? :)

Ну в общем, да. Есть такое божество, Условия Заказчика называется :))) На самом деле ситуация такая: приходит текстовый файл - отчет от пропускной системы (турникеты с карточками). Его нужно переварить как можно быстрее на довольно слабой тачке (на которой и офиса-то может не быть).


 
Brenagwynn   (2005-02-04 14:26) [12]


> AssignFile + Readln + F1

Ой. А у меня такое подозрение, что это будет один из самых медленных способов.


 
Александр Иванов ©   (2005-02-04 14:28) [13]

Brenagwynn   (04.02.05 14:26) [12]
Какая разница, через что, все способы внутри будут содержать либо ReadLn, либо ReadBuffer. Второй быстрей, поэтому я тебе его и порекомендовал.


 
Brenagwynn   (2005-02-04 14:35) [14]


> Александр Иванов ©   (04.02.05 14:28) [13]
> Какая разница, через что, все способы внутри будут содержать
> либо ReadLn, либо ReadBuffer.


...или к ReadFile. Согласен.


 
Александр Иванов ©   (2005-02-04 14:37) [15]

Brenagwynn   (04.02.05 14:35) [14]
Согласен.

Тогда см. [4] :).


 
Brenagwynn   (2005-02-04 15:21) [16]

Результаты тестов (50000 строк, файл 3 Мб):
одной строкой - 73145 мсек
стринглист - 73736 мсек
Вывод: в общем, эквипенисуально. Но стринглистом удобнее.


 
Александр Иванов ©   (2005-02-04 15:23) [17]

Brenagwynn   (04.02.05 15:21) [16]
Ты спрашивал, самый быстрый способ. И потом еще список может уступать, правда на совсем немного, в скорости доступа к строкам.


 
Brenagwynn   (2005-02-04 15:26) [18]


> Александр Иванов ©   (04.02.05 15:23) [17]
> И потом еще список может
> уступать, правда на совсем немного, в скорости доступа к
> строкам.

Ну, вот так оно и есть. Немного. А 700 мсек я готов пожертвовать в пользу удобства. Если бы была разница секунд в 5 - тогда другое дело.


 
Александр Иванов ©   (2005-02-04 15:33) [19]

Brenagwynn   (04.02.05 15:26) [18]
А в чем удобстве? Так просто добавится еще один разделитель - #10#13.


 
Brenagwynn   (2005-02-04 15:39) [20]

Через стринглист:

with TStringList.Create do
try
 LoadFromFile("d:\apacs.txt");
 for i := 0 to Count-1 do
   ParseString(Strings[i],#9); // собственно парсим строку
finally
 Free;
end;

Без стринглиста:

with TFileStream.Create("d:\ing.txt", fmOpenRead or fmShareDenyWrite) do
try
 StrSize := Size - Position;
 SetString(S, nil, StrSize);
 Read(Pointer(S)^, StrSize);
 P := Pointer(S);
 if P <> nil then
   while P^ <> #0 do
   begin
     Start := P;
     while not (P^ in [ #0, #10, #13]) do Inc(P);
     SetString(sub, Start, P - Start);
     ParseString(sub,#9);
     if P^ = #13 then Inc(P);
     if P^ = #10 then Inc(P);
   end;
finally
 Free;
end;

Имхо, первое как-то компактнее выглядит.


 
TUser ©   (2005-02-04 15:42) [21]

Стринглист работает в чертово количество раз быстрее, чем readln


 
Александр Иванов ©   (2005-02-04 15:43) [22]

А для одной строки, пользуясь почти твоими терминами (Str - исходная строка):
ParseString(Str,[ #9,#10,#13]);


 
Александр Иванов ©   (2005-02-04 15:44) [23]

TUser ©   (04.02.05 15:42) [21]
Я советовал ReadBuffer


 
Brenagwynn   (2005-02-04 15:46) [24]


> Александр Иванов ©   (04.02.05 15:43) [22]
> А для одной строки, пользуясь почти твоими терминами (Str
> - исходная строка):
> ParseString(Str,[ #9,#10,#13]);

То есть весь вышеприведенный код затолкать в одну процедуру. Можно, конечно... Ну да и фиг с ним.


 
Alx2 ©   (2005-02-04 15:48) [25]

>Brenagwynn   (04.02.05 15:39) [20]

Увеличить скорость чтения из файла "с помощью readln" поможет
SetTextBuf (см Help).

Если разделители стандартные, то можно непосредственно читать значение переменной с помощью read/readln


 
Александр Иванов ©   (2005-02-04 15:49) [26]

Brenagwynn   (04.02.05 15:46) [24]
Ты не понял, в твоей процедуре ParseString, необходимо будет только изменить условия с =, на in и внешнего цикла по строкам StringLista не будет.


 
Brenagwynn   (2005-02-04 16:06) [27]


> Александр Иванов ©   (04.02.05 15:49) [26]
> Ты не понял, в твоей процедуре ParseString, необходимо будет
> только изменить условия с =, на in и внешнего цикла по строкам
> StringLista не будет.

Спасибо, помогло, да еще и как: 5800 мсек вместо 73145 мсек!


 
Александр Иванов ©   (2005-02-04 16:09) [28]

Александр Иванов ©   (04.02.05 15:23) [17]
И потом еще список может уступать, правда на совсем немного, в скорости доступа к строкам.

Значит в этом я ошибся.


 
Brenagwynn   (2005-02-04 16:21) [29]


> Александр Иванов ©   (04.02.05 16:09) [28]
> И потом еще список может уступать, правда на совсем немного,
> в скорости доступа к строкам.
> Значит в этом я ошибся.

Как раз нет. При использовании ОДНОЙ И ТОЙ ЖЕ процедуры парсинга получаются примерно одни результаты. А вот если отказаться от нее и написать так:

colCount := 1;
rowCount := 1;
P := Pointer(S);
if P <> nil then
 while P^ <> #0 do
 begin
   Start := P;
   while not (P^ in [ #0, #9, #10, #13]) do Inc(P);
   SetString(sub, Start, P - Start);

   if P^ = #9 then begin
     Inc(P);
     Inc(colCount); // новый столбец
   end;
   if P^ = #13 then Inc(P);
   if P^ = #10 then
   begin
    Inc(P);
    colCount := 1;
    Inc(rowCount); // новая строка
   end;
 end;

получается гаааараздо быстрее. У меня еще и ParseString был весьма тормозной (через Copy - Delete).


 
Alex_Bredin ©   (2005-02-04 16:33) [30]

Parsestring можно тоже сделать одной строкой - Stringlist.commatext := строка и готово


 
Игорь Шевченко ©   (2005-02-04 16:35) [31]

TUser ©   (04.02.05 15:42) [21]


> Стринглист работает в чертово количество раз быстрее, чем
> readln


Странно. У тебя наверное импортный StringList. Или военный.

type
 TForm1 = class(TForm)
   Label1: TLabel;
   Label2: TLabel;
   lbReadln: TLabel;
   lbStringList: TLabel;
   Button1: TButton;
   Button2: TButton;
   procedure Button1Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
 end;

var
 Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
 F: TextFile;
 Start: DWORD;
 Buffer: string;
begin
 Start := GetTickCount;
 AssignFile(F, "test.txt");
 Reset(F);
 try
   while not Eof(F) do
     readln(F, buffer);
 finally
   CloseFile(F);
 end;
 lbReadln.Caption := IntToStr(GetTickCount - Start);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
 List: TStringList;
 Start: DWORD;
begin
 Start := GetTickCount;
 List := TStringList.Create;
 List.LoadFromFile("test.txt");
 lbStringList.Caption := IntToStr(GetTickCount - Start);
end;

end.


Результаты - readln - 390-410 тиков, stringlist - 700-1500 тиков.

Файл test.txt имеет 614 тысяч строк, размер 30 мегабайт.


 
Brenagwynn   (2005-02-04 16:36) [32]


> Alex_Bredin ©   (04.02.05 16:33) [30]
> Parsestring можно тоже сделать одной строкой - Stringlist.commatext
> := строка и готово

Тогда уж DelimitedText и Delimiter (у меня поля отделяются табуляцией). Думаю, что это будет все-тки медленнее (надо будет тоже попробовать).


 
Digitman ©   (2005-02-04 17:24) [33]


> Игорь Шевченко ©   (04.02.05 16:35) [31]
> Странно. У тебя наверное .. StringList...военный


точно, Игорь.
не иначе как прапорщик СА по заказу Борланда писал этот класс.


> TUser ©   (04.02.05 15:42) [21]


а куда ему, прапорщику, деваться ?

вынужден он, понимаешь ли, при  каждом add-вызове перераспределять память ..


 
Игорь Шевченко ©   (2005-02-04 17:33) [34]

Digitman ©   (04.02.05 17:24) [33]


> вынужден он, понимаешь ли, при  каждом add-вызове перераспределять
> память


Написано, кстати, действительно неоптимально. Для небольших объемов еще незаметно, а вот для более/менее солидных уже проявляются побочные эффекты.

Я удивляюсь современным программистам - скоро для удаления пробелов в строке будут WordApplication использовать. И непременно через супер-пупер компонент.

С уважением,


 
Digitman ©   (2005-02-04 17:57) [35]


> Игорь Шевченко ©   (04.02.05 17:33) [34]


прапорщику и задача-то иная ставилась, так ведь ?
TStringList вовсе не для таких объемов данных планировался ..
для оперативной и быстрой обработки ..

ну штука строк, ну другая .. ну уж никак не сотни, сотни тысяч штук строк ..

мозжечком шевелить таки надо ..


 
имя   (2005-02-04 18:26) [36]

Удалено модератором



Страницы: 1 вся ветка

Текущий архив: 2005.02.20;
Скачать: CL | DM;

Наверх




Память: 0.56 MB
Время: 0.049 c
14-1106895441
MBo
2005-01-28 09:57
2005.02.20
Пятничные задачки. ;)


14-1107155585
TUser
2005-01-31 10:13
2005.02.20
Бейсик


4-1104321154
TankMan
2004-12-29 14:52
2005.02.20
Вот почему не работает WMI при установке винды?


1-1107871471
AL_
2005-02-08 17:04
2005.02.20
Фискальный регистратор


4-1103998049
Flext@r
2004-12-25 21:07
2005.02.20
Получение списка выполняемых задач винды