Форум: "WinAPI";
Текущий архив: 2004.12.12;
Скачать: [xml.tar.bz2];
ВнизFileMapping Найти похожие ветки
← →
IronRat (2004-10-30 18:21) [0]Привет,
была поставлена задача поиск строки в файлах, и в общем-то все работает, до момента, когда моя программа при переборе файлов натыкается на STRING.H из библиотеки BC3.1 :(
вылетает на этой строке
Address := pChar(MapFilePointer);
i := Pos(SearchString,Address);
точнее на i := Pos(SearchString,Address). Вот.
Вылетает при любой дислокации файла STRING.H.
Было ощущение, что Pos возвращает слишком большое значение, но int64 для i не помогло. Да и сам файл всего 8 кило.
Подскажите, в чем может быть проблема?
← →
Игорь Шевченко © (2004-10-30 18:27) [1]
> моя программа вылетает на этой строке
> Подскажите, в чем может быть проблема?
В программе, разумеется.
Я бы посоветовал поиск организовать иначе, чем использованием функции Pos, например, побайтовым сравнением, с учетом размера спроецированного файла, чтобы при сравнении не выйти за его границу.
← →
Ihor Osov'yak © (2004-10-30 21:58) [2]try it:
function GetViewFile(aFileName: string; var aBuff: pointer; var aSize: integer): boolean;
var
fh: THandle; // file handle
fm: THandle; // File mapping handle
begin
result := false;
aBuff := nil;
aSize := 0;
if not FileExists(aFileName) then
exit;
fh := CreateFile(PChar(aFileName), GENERIC_READ, 0, nil,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
if fh = INVALID_HANDLE_VALUE then
exit;
aSize := GetFileSize(fh, nil);
fm := CreateFileMapping(fh, nil, PAGE_READONLY, 0, 0, nil);
CloseHandle(fh);
if fm = 0 then
exit;
aBuff := MapViewOfFile(fm, FILE_MAP_READ, 0, 0, 0);
result := assigned(aBuff);
end;
function FindSubstrInBuff(const Buff: pointer; SubStr: AnsiString; DimBuff: integer): integer;
asm
// EAX = Buff, EDX = addr SubSTR, ECX = DimBuff
PUSH EDI
PUSH ESI
PUSH EBX
PUSH EAX
OR EAX,EAX
JE @@2 // Buff = nil
OR EDX,EDX
JE @@2 // SubStr = nil
OR ECX,ECX
JE @@2 // size = nil
MOV EBX, ECX
SUB EBX,[EDX-4]
JL @@2
INC EBX
MOV ECX,EBX
MOV EBX,[EDX-4]
DEC EBX
MOV EDI,EAX
@@1: MOV ESI,EDX
LODSB
REPNE SCASB
JNE @@2
MOV EAX,ECX
PUSH EDI
MOV ECX,EBX
REPE CMPSB
POP EDI
MOV ECX,EAX
JNE @@1
LEA EAX,[EDI-1]
POP EDX
SUB EAX,EDX
INC EAX
JMP @@3
@@2: POP EAX
XOR EAX,EAX
@@3: POP EBX
POP ESI
POP EDI
end;
использование - сначала GetViewFile, потом FindSubstrInBuff.
Помнить о UnmapViewOfFile для указателя, полученого через var aBuff: pointer..
← →
Ihor Osov'yak © (2004-10-30 22:01) [3]да, кажется нужно также закрывать fm, то есть
вместо
aBuff := MapViewOfFile(fm, FILE_MAP_READ, 0, 0, 0);
result := assigned(aBuff);
должно быть
aBuff := MapViewOfFile(fm, FILE_MAP_READ, 0, 0, 0);
CloseHandle(fm);
result := assigned(aBuff);
иногда полезно постить куски кода, над которыми сейчас работаешь :-).
← →
IronRat (2004-10-30 23:54) [4]я ассемблер конечно люблю :)
но при случае предпочитаю обходиться без него...
исправляюсь к последнему замечанию ("иногда полезно постить куски кода, над которыми сейчас работаешь :-)."):
function FileMappingFunc(FileName: string; SearchString: string): boolean;
begin
hFile := CreateFile(pChar(FileName), GENERIC_READ, FILE_SHARE_READ and FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if hFile <> INVALID_HANDLE_VALUE then
begin
hMapFile := CreateFileMapping(hFile, nil, PAGE_READONLY, 0, 0, nil);
if hMapFile <> 0 then
begin
MapFilePointer := MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
if MapFilePointer <> nil then
begin
Address := pChar(MapFilePointer);
i := Pos(SearchString,Address);
UnMapViewOfFile(MapFilePointer);
end
else
SubStr := False;
CloseHandle(hMapFile);
end;
if i = 0 then
SubStr := False
else
SubStr := True;
CloseHandle(hFile);
end
else
SubStr := False;
end;
end;
проблема явная, провереная не на один раз:
i := Pos(SearchString,Address);
тут он падает на 1 файле из миллиона (образно). я нашел 2 таких файла. на мой взгляд они _НИЧЕМ_ не примечательны.
← →
GuAV © (2004-10-31 00:27) [5]
> function FindSubstrInBuff(const Buff: pointer; SubStr:
> AnsiString; DimBuff: integer): integer;
http://dennishomepage.gugs-cats.dk/FastCodeProject.htm
ищите там PosChallenge ;)
← →
IronRat (2004-10-31 01:40) [6]GuAV нашел, посмотрел, не понял, как это может помочь мне...
:(
← →
GuAV © (2004-10-31 01:52) [7]Блин, забыл написать, не Вам, а 2 Ihor Osov"yak. Он написал свою Pos на asm, так я указал где ещё лучше найти.
← →
Ihor Osov'yak © (2004-10-31 03:54) [8]2 [7] GuAV © (31.10.04 01:52)
Спасибо. Код FindSubstrInBuff, собственно не совсем мой, я его в свое время увидел на каком-то форуме, немного адаптировал.. Автора оригинального кода к сожалению не запомнил...
2 IronRat
> вылетает на этой строке
знаете, было бы не лишним указать текст сообщения об ошибке. Это во первых. Во вторых, желательно упомянуть тип SearchString,Address...
Понятно, что это либо PChar либо стринг. Но и в том и в том случае в Вашем коде будут присутсвовать неявные копирования блоков памяти в процессе преобразования между строками вида PChar и string, что значительно снижает быстродействие, то есть выиграш от отображения файла в память.
Также не совсем оптимален набор атрибутов при открытии файла. Но это так, между прочим..
А теперь к основному вопросу - почему вылет.. Кстати, файлик то читается? Попробуйте его скопировать куда-то.. Я это к тому, что в случае, если Address - PChar, то реальная подчитка файла будет осуществлятся при преобоазоварнии PChar в стринг в процессе подготовки параметров для Pos вот в этой чудненькой строчке -
i := Pos(SearchString,Address);
и здесь вполне может быть ошибка ввода-вывода..
← →
IronRat (2004-10-31 11:12) [9]2 Ihor Osov"yak:
да, Address типа PChar, а SearchString типа string...
видимо проблема в этом, но избавиться-то от нее как?
← →
IronRat (2004-10-31 11:17) [10]2 Ihor Osov"yak:
кстати, я уже писал, что файл читается.
а ошибка происходит при любой дислокации файла.
ошибка такая:
"Project Search.exe raised exception class EAccessViolation with message "Access violation at address 04044aAF in module "Search.exe". Read of address 00A92000" Process stopped."
← →
Ihor Osov'yak © (2004-10-31 12:17) [11]2 [10] IronRat (31.10.04 11:17)
блин..
ларчик открывается довольно просто. Для нормального преобразования PChar в string (а это происходит перед передачей параметров в Pos, я веду спич о Address) нужно чтобы первый оканчивался символом с кодом 0. А у Вас - это не совсем так. Вся область памяти, на которую указывает Address в процессе преобразования будет сканироваться до встречи первого 0, и все, что встретилось до того - будет интерпритироваться как строка. То есть до отражения файла в процессе преобразования будет присоединяться куча всякого хлама, до встречи первого 0-символа после конце отражения. В случае с STRING.H Вам просто "повезло" - просто в области хлама 0-символ не был встречен и Вы нарвались на границу распределенного блока памяти. Вполне возожно, что при мапировании файлов память становится доступной блоками, размер которых кратен страницам + размер соотв. файла - кратен странице и следовательно сразу же за окончанием отражения - память не распределена (это версия) - а функция преобразования PChar в ансистринг родолжает свою работу. И как следствие - Access violation..
итого резюме - возьмите код, который я Вам привел и не партесь. Хотя бы потому что ваша реализация очень неоптимальна - выше я уже объяснал почему - ну и плюс неочевидная ошибка, также которая прокоментирована
абзацем выше..
зы. собственно я немного больше разжевал то, что уже было концептуально сформулировано в [1]..
← →
Ihor Osov'yak © (2004-10-31 12:20) [12]Вполне возожно -> Вполне возможно...
и даже не возможно - а очевидно, что так - так как у вас результат повторяем.. Посмотрите размер этого STRING.H - могу поспорить, что он кратен 4096 :-)
← →
IronRat (2004-10-31 12:54) [13]2 Ihor Osov"yak:
:)))
8192...
да.
Спасибо большое. Ошибка ясна, будем исправляться :)
← →
Ihor Osov'yak © (2004-10-31 13:15) [14]2 IronRat
Вы всеже откажитесь от использования Pos (в основном из-за того, что там как не крути, не избежать преобразования PChar -> string, а это время - это для Вас наверное критично, раз начали отражения делать..). Для экспреиманта - сравните быстродействие с Pos и без - например мою реализацию (один из вариантов - запустите цыкл с несколькими тысячими реализаций). Результат Вас должен впечатлить.
Еще - реализации, которые по ссылке от [5] GuAV © - значительно более быстрые - но они все же ориентированы на работу со String, а у Вас - буфер. Если делать преобразование - то снова потери, которые сводят на нет все преимущества более быстрой реализации. Посему отталкивайтесь от кода, приведенного мной, или займитесь адаптацией (переход от string к буферу с указанием размера) от ссылки [5] GuAV - но там код далеко не тривиальный.
← →
Ihor Osov'yak © (2004-10-31 13:16) [15]несколькими тысячими реализаций - несколькими тысячими итераций.
Извините.
← →
IronRat (2004-10-31 13:50) [16]2 Ihor Osov"yak ©:
с ассемблером я вряд ли разберусь :(
да и время поиска для меня не так уж критично...
предпочтительней, наверно, это:
"или займитесь адаптацией (переход от string к буферу с указанием размера)".
Но что-то я пока не представляю как это сделать.
← →
IronRat (2004-10-31 13:55) [17]так?
function BinaryToStr(PBuffer:Pointer;size:integer;Delimiter:char):string;
{преобразование последовательности байтов в строку
PBuffer - указатель на начало двоичной области
Size - количество байт}
var
s:string;
i:integer;
begin
result:="";
for i:=0 to Size-1 do begin
s:=inttohex((PByteArray(PBuffer))^[i],2);
if (Delimiter<>#0) then s:=s+Delimiter;
Result:=Result+s;
end;
if (Result<>"")and(Delimiter<>#0)then setlength(Result,length(Result)-1);
end;
код не мой... :)
← →
IronRat (2004-10-31 14:12) [18]или блин... не знаю даже.
наверно не надо в ansistring преобразовывать... она же ограничена 2^31... а мне бы без ограничений, не зря же я отображение использовал.
← →
Ihor Osov'yak © (2004-10-31 14:57) [19]2 [17] IronRat (31.10.04 13:55)
блин, что за ахинея. Я в шоке. Это с привода function BinaryToStr(PBuffer:Pointer;size:integer;Delimiter:char):string;
не вобще, а применительно к Вашему случаю. Это во первых. Во вторых - хотел бы я посмотреть, как Вы сматируете в память файл, размером больше "2^31". В Win32 во всяком случае.
Повторяю раз четверый наверно - ничего преобразовывать не нужно. Искать в буфере без преобразований. С учетом размера буфера. Один из примеров реализации такого поиска я привел. Берите и используйте. И извините за прямоту - у меня подозрения, что Ваши познания в паскале не сильно убежали от Ваших познаний в ассемблере.
И еще. Большая просьба. Если уже немного ушли от компонентобросания - почитайте книжки. Не Архангельского. Последствия чтения последнего автора порою неисправимы за всю последующую жызнь.
← →
IronRat (2004-10-31 15:04) [20]2 Ihor Osov"yak:
Спасибо.
← →
Ihor Osov'yak © (2004-10-31 15:21) [21]2 [20] IronRat (31.10.04 15:04)
А знаете, я почему-то верю, что у Вас все получится.
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2004.12.12;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.039 c