Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2005.02.20;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.037 c
3-1106449961
SarDoX
2005-01-23 06:12
2005.02.20
Поиск в БД


3-1106292019
sergg
2005-01-21 10:20
2005.02.20
Ошибка: В операции должен использоваться обновляемый запрос


4-1105140062
Mr.Devil
2005-01-08 02:21
2005.02.20
Права доступа


3-1106645184
DimonNew
2005-01-25 12:26
2005.02.20
Проверить - существует ли параметр в ADOCommand


3-1106157989
ВиТ
2005-01-19 21:06
2005.02.20
печать структуры бд





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский