Текущий архив: 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.54 MB
Время: 0.05 c