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

Вниз

Поиск последовательности байт в файле.   Найти похожие ветки 

 
3223(jab)   (2003-05-07 10:55) [0]

Люди добрые, помогите ускорить процесс поиска определённой последовательности байт в файле.

Осуществляю поиск следующим образом:

procedure TForm1.Button1Click(Sender: TObject);
var
i:Integer;
FStream:TFileStream;
begin
Button1.Enabled:=False;
FStream:=TFileStream.Create(OpenDialog1.FileName,fmOpenRead);
StatusBar1.SimpleText:="Длинна файла="+IntToStr(FStream.Size-1);
//
for i:=0 to FStream.Size-1 do begin
FStream.Position:=i;
FStream.Read(data,sizeof(data));
ProgressBar1.Max:=FStream.Size-1;
ProgressBar1.Position:=i;
find(i);
Application.ProcessMessages;
end;
//
ListView1.Items.Add.Caption:=IntToStr(FileSize(f1)-1);
FStream.Free;
Button1.Enabled:=True;
end;

procedure TForm1.find(i:Integer);
begin
case data of
$57: a:=1;
$41: a:=a+1;
$56: a:=a+1;
$45: begin if a=3 then ListView1.Items.Add.Caption:=IntToStr(i-11); a:=0; end
else a:=0; end;
end;

Очень медленно получается! Может есть примерчик или какими функциями можно воспользоваться или вообще реально ускорить поиск?


 
evvcom ©   (2003-05-07 11:03) [1]

Читаешь в буфер и AnsiStrPos


 
Leshiy ©   (2003-05-07 11:06) [2]

Читать из файла блоками больше чем 1 байт.


 
ASMiD ©   (2003-05-07 11:17) [3]

Leshiy прав
Сначала читаеш все данные из потока в память, и только потом начинаеш проверять.
А то - нард жалко.


 
evvcom ©   (2003-05-07 11:27) [4]


> Сначала читаеш все данные из потока в память

Все может и не получиться. Но в цикле, например, по 64 тыс. байт - нормально. Только учти, что искомая комбинация может попасть на конец текущего/начало следующего блока, поэтому читать, например, по 64004 байт, а потом возвращаться на 4 байта назад (такая вроде длина искомой строки) и следующий блок читать с позиции 64000.


 
ASMiD ©   (2003-05-07 11:45) [5]

А что нельзя считать все сразу?


 
evvcom ©   (2003-05-07 11:57) [6]


> А что нельзя считать все сразу?

А если файл на Гиг? Ведь возможно и такое. И такая маленькая программка сожрет всю память!


 
3223(jab)   (2003-05-07 12:31) [7]

У меня файлы по 500 -700 Мегобыйт.

>Читаешь в буфер и AnsiStrPos

Это как понимать? Ну читать в буфер можно я так понял
var
buf:^Byte;
begin
GetMem(buf,64004);
...
FreeMem(buf,64004);
end;
А куда приделать AnsiStrPos ??????


 
3223(jab)   (2003-05-07 12:37) [8]

Мне добрые люди посоветовали воспользоваться АПИ функциями:
CreateFileMapping, MapViewOfFile

Пока ничего хорошего из этого не вышло! Может кто чего подскажет по этому поводу?


 
evvcom ©   (2003-05-07 12:51) [9]

var
Buf: array[0..64004] of Char;
pPos: PChar;
begin
// ... цикл пока не конец файла
FStream.Read(Buf, sizeof(Buf));
pPos := AnsiStrPos(Buf[0], #57#41#56#45);
if Assigned(pPos) then begin
// Ура нашел!
// Break или Exit
end;
// цикл
end;


А с CreateFileMapping, наверное, действительно побыстрее получится, избавишься от двойного копирования, но дальнейший поиск все равно так же. Описаны эти функции то ли в книге Джефри Рихтер "Windows для профессионалов", то ли в книге Тейксера и Пачеко. В любом случае хорошие книги, поищи.


 
3223(jab)   (2003-05-07 14:10) [10]

to evvcom
Спасибо за разьяснение!
А книги конечно хорошие и стоят они наверно не плохо! :)

Гдеб их на шару урвать...


 
3223(jab)   (2003-05-07 14:15) [11]

Джеффри РИХТЕР "Windows для профессионалов" - нашел!
Каму надо могу сказать где искать.
Искать на страничке у Анатолия Подгорецкого, за что ему огромное спасибо! :)


 
MBo ©   (2003-05-07 14:15) [12]

>3223(jab)

Загляни в
http://delphimaster.net/view/1-1052141053/
и под себя модифицируй


 
ND   (2003-05-07 16:42) [13]

>evvcom
Код хороший, только чуть нужно подправить .
Вот только - как найти номер байта начиная с которого совпадает с которого появляется в файле эта послед-ть байтов.

Задача как правило именно такая.

Все равно получается нужен перебор или можно как-то вычислить из модифицировав твой код.


 
3223(jab)   (2003-05-07 16:50) [14]

to evvcom
Да действительно! ND прав! Мне не удалось определить адрес. + заругалось на pPos:=AnsiStrPos(Buf[0],#57#41#56#45); [Error] Unit1.pas(239): Incompatible types: "Char" and "PChar" - это я обойти смог pPos:=AnsiStrPos(PChar(Buf[0]),#57#41#56#45); только какая то белеберда вышла!
to MBo спасибо, посмотрю, попробую!


 
evvcom ©   (2003-05-07 16:57) [15]


> Вот только - как найти номер байта начиная с которого совпадает
> с которого появляется в файле эта послед-ть байтов.

Посчитать! Возвращает PСhar на найденную последовательность. Из этого DWORD(Pchar) отнять DWORD(@Buf[0]) получишь индекс позиции. Может DWORD(Buf) тоже пройдет (сомнения)?.. Адреса сравнивать нельзя - компилятор ругается, а после приведения типов к Integer или DWORD можно.


 
evvcom ©   (2003-05-07 17:04) [16]


> Да действительно! ND прав! Мне не удалось определить адрес.
> + заругалось на pPos:=AnsiStrPos(Buf[0],#57#41#56#45); [Error]
> Unit1.pas(239): Incompatible types: "Char" and "PChar" -
> это я обойти смог pPos:=AnsiStrPos(PChar(Buf[0]),#57#41#56#45);
>

Прошу прощения, спутал с Move(var Buf; ...). Здесь ведь PChar.
Здесь надо pPos:=AnsiStrPos(Buf,#57#41#56#45); или pPos:=AnsiStrPos(@Buf[0],#57#41#56#45); но по-моему и первый вариант пройдет.


 
evvcom ©   (2003-05-07 17:08) [17]

Еще может возникнуть проблема. Если в файле встретится нулевой байт, то для PChar - это конец строки. На нем AnsiStrPos прекратит поиск.


 
ND   (2003-05-07 17:18) [18]

>evvcom

>Посчитать! Возвращает PСhar на найденную последовательность. Из >этого DWORD(Pchar) отнять DWORD(@Buf[0]) получишь индекс >позиции. Может DWORD(Buf) тоже пройдет (сомнения)?.. Адреса >сравнивать нельзя - компилятор ругается, а после приведения >типов к Integer или DWORD можно.

Не пойму объясни подробнее.


 
3223(jab)   (2003-05-07 17:49) [19]

Эээ, а как это сделано в Hex эдиторах? (16 ричных просмотрщиках)


 
default ©   (2003-05-07 18:56) [20]

можно сделать вроде этого:
читаете данные из файла "как послед-ть символов"
и среди них быстрым алгоритмом поиска подстроки в строке
производите поиск
только станд-ые ф-ии не используйте типа Pos, IndexOf(в потомках TStrings)...
это всё - обычный перебор - и для твоих размеров файлов с таким "крутым"
методом поиска программа будет очень тормозной...
при этом учитывай замечание evvcom © (07.05.03 11:27)


 
vgb ©   (2003-05-07 20:00) [21]

To 3223(jab)

> Джеффри РИХТЕР "Windows для профессионалов" - нашел!
> Каму надо могу сказать где искать.
> Искать на страничке у Анатолия Подгорецкого, за что ему
> огромное спасибо! :)

Link ne dadite?
A to zadolbalsa iskat"


 
evvcom ©   (2003-05-07 23:33) [22]


> А книги конечно хорошие и стоят они наверно не плохо! :)
>
> Гдеб их на шару урвать...

Стоят неплохо, но есть и нахаляву http://delphiplus.nagano.ru/DocsDelphi5.html (Тейксейра и Пачеко)


 
evvcom ©   (2003-05-08 08:03) [23]

>
> >Посчитать! Возвращает PСhar на найденную последовательность.
> Из >этого DWORD(Pchar) отнять DWORD(@Buf[0]) получишь индекс
> >позиции. Может DWORD(Buf) тоже пройдет (сомнения)?.. Адреса
> >сравнивать нельзя - компилятор ругается, а после приведения
> >типов к Integer или DWORD можно.
>
> Не пойму объясни подробнее.

pPos := AnsiStrPos(Buf, #57#41#56#45);
if Assigned(pPos) then begin
// Ура нашел!
iPosIndex := DWORD(pPos) - DWORD(Buf); // Приведение адресов к DWORD, так как PChar, Pointer и др.адресные типы нельзя сравнивать, складывать и т.д.
// Break или Exit
end;</CODE


 
ND   (2003-05-08 12:52) [24]

>evvcom

я пробовал

pPos := AnsiStrPos(Buf, #57#41#56#45);
if Assigned(pPos) then begin
// Ура нашел!
iPosIndex := DWORD(pPos) - DWORD(Buf); // Приведение адресов к DWORD, так как PChar, Pointer и др.адресные типы нельзя сравнивать, складывать и т.д.
// Break или Exit
end;</CODE

dword(pPos) и DWORD(Buf) - на моем компе всегда одни те же значения не зависящие от того где найдена послед-ть.

Ppos - это же по сути переменная - а значит по сути копируется
найденная послед-ть байтов и соответственно по ней адреса вхождения не найдешь


 
evvcom ©   (2003-05-08 14:12) [25]

2ND: Прогнал сейчас в Дельфях то, что писал выше. Единственное, что все же поправил, это DWORD(Buf) заменил на DWORD(@Buf[0]), о чем я выше и выражал сомнения. Итого код абсолютно работоспособный:
procedure TForm1.Button1Click(Sender: TObject);
var
Buf: array[0..100] of Char;
pPos: PChar;
iPosIndex: Integer;
begin
Buf := "абракадабра непонятная "#57#41#56#45" абракадабра непонятная";
pPos := AnsiStrPos(Buf, #57#41#56#45);
if Assigned(pPos) then begin
// Ура нашел!
iPosIndex := DWORD(pPos) - DWORD(@Buf[0]);
// дальнейшие вычисления с использованием iPosIndex
end;
end;

Только оптимизацию из опций проекта убери, а то соптимизирует, что до iPosIndex не доберешься по причине его дальнейшего неиспользования в данном примере.



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

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

Наверх




Память: 0.53 MB
Время: 0.011 c
1-70257
qw
2003-05-12 11:56
2003.05.22
Services


1-70269
zom
2003-05-07 14:04
2003.05.22
Как нарисовать окно, которое всегда на переднем плане?


1-70323
Silver_
2003-05-08 14:35
2003.05.22
EhLib SumList когда Master -> Detail


3-70154
Belkova
2003-05-02 11:09
2003.05.22
Скролинг


14-70483
race1
2003-05-02 06:29
2003.05.22
Typematic