Подскажите пожалста, как в ассемблере осуществить поиск файла, не только в текущем каталоге, но и к примеру по всему диску C:\ или D:\ . Зарание спасибо
спасибо всем, пожалуй совет на счёт рекурсивных процедур самый верный(уже читаю). А на счёт этих API функций, на которые все пачамут молятся, так я их как то не очень уважаю, хочется всё вручную делать, так понятнее)
хочется всё вручную делать дык напиши свой драйвер файловой системы и работай с ним, коль апи не устраивают
А это, чтобы проще осваивалось. Простой код рекурсивного поиска файла по винту. Code (Text): ; -=-=-=-=-=-=-=-=-=-=-=-=-=- ; Global files search in MASM ; Created by Ct757 ; -=-=-=-=-=-=-=-=-=-=-=-=-=- ; ; Use MASM to compile this shit ; ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; В данном примере показана рекурсивная реализация ; поиска файлов на ассемблере под Windows с помощью ; API-функций FindFirstFile + FindNextFile, а так же ; показано как можно узнать список присутствующих ; в системе дисков с помощью функции GetLogicalDrives ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .386 .model flat, stdcall option casemap:none include \masm32\include\windows.inc include \masm32\include\kernel32.inc include \masm32\include\user32.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib .data ; Секция данных buf db 500h dup(?) ; Буффер для имени директории fake1 db '.',0 ; Директории, которые fake2 db '..',0 ; НЕ надо сканировать .code ; Секция кода find_files proc ; Рекурсивная процедура ; Поиска файлов push ebp ; Выделим место в стеке mov ebp,esp ; под хэндл поиска sub esp,144h ; и структуру WIN32_FIND_DATA lea eax,[ebp-144h] ; Вычисляем указатель на find_data invoke FindFirstFile,offset buf,eax ; Ищем файлы inc eax ; Если ничего je exit ; не нашли - выходим dec eax ; Иначе, сохраним mov dword ptr [ebp-6h],eax ; хэндл поиска find_next: mov eax,dword ptr [ebp-144h] ; Проверяем, нашли and eax,FILE_ATTRIBUTE_DIRECTORY ; директорию? je found ; Если нет - прыгаем на found lea eax,[ebp-118h] ; Вычислим указатель на cFileName invoke lstrcmp,offset fake1,eax ; это "."? test eax,eax ; Если да, je next ; ищем дальше lea eax,[ebp-118h] ; Вычислим указатель на cFileName invoke lstrcmp,offset fake2,eax ; это ".."? test eax,eax ; Если да, je next ; ищем дальше invoke lstrlen,offset buf ; Вычислим длину строки sub eax,3 ; Вычтем *.* push eax ; Сохраним полученную длину mov byte ptr [buf+eax],0 ; Если мы всё-таки нашли lea eax,[ebp-118h] ; директорию, то прибавим invoke lstrcat,offset buf,eax ; к её имени cFileName invoke lstrlen,offset buf ; Вычислим длину строки mov dword ptr [buf+eax],'*.*\' ; Прибавим \*.* mov byte ptr [buf+eax+4],0 ; для поиска call find_files ; Вызываем процедуру поиска ; для найденной директории pop eax ; Восстановим дляну строки mov dword ptr [buf+eax-1],'*.*\' ; И восстановим \*.* mov byte ptr [buf+eax+3],0 ; jmp next ; Ищем дальше found: lea eax,[ebp-118h] ; Вычислим длину invoke lstrlen,eax ; cFileName cmp dword ptr [ebp-118h+eax-4],'txt.' ; Проыерим расширение файла jne next ; Если не равно ищем дальше lea eax,[ebp-118h] ; Если нашли, то что нужно invoke MessageBox,0,eax,eax,0 ; Покажем MessageBox с именем файла next: lea eax,[ebp-144h] ; Вычислим указатель на find_data invoke FindNextFile,dword ptr [ebp-6h],eax ; Ищем следующий файл test eax,eax ; jne find_next ; Если ничего не нашли invoke FindClose,dword ptr [ebp-6h] ; Закрываем хэндл поиска exit: leave ; Выходим из ret ; процедуры find_files endp start: invoke SetErrorMode,SEM_FAILCRITICALERRORS ; Установим error mode ; чтобы в случае обращения ; к недоступному диску ; не вываливалось сообщение invoke GetLogicalDrives ; Получаем список дисков ; существующих в системе mov ecx,25 ; Будем проверять, начиная с Z:\ find_drives: mov ebx,1 ; Нехитрые операции в shl ebx,cl ; ходе которых мы выясняем and ebx,eax ; присутсвует диск в je no_disk ; системе или нет ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; На всякий случай, пояснение из MSDN: ; ; ;---------------------------------; ; ; DWORD GetLogicalDrives(void); ; ; ;---------------------------------; ; ; Return Values: ; -------------- ; If the function succeeds, the return value is a bitmask ; representing the currently available disk drives. ; Bit position 0 (the least-significant bit) is drive A, ; bit position 1 is drive B, bit position 2 is drive C, and so on. ; ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ add cl,65 ; Если да, то mov byte ptr buf,cl ; добавим букву sub cl,65 ; диска в буффер mov dword ptr buf+1,'.*\:' ; Сформируем строку mov byte ptr buf+5,'*' ; для поиска, вида, mov byte ptr buf+6,0 ; например, C:\*.* push eax ; Сохраняем нужные push ecx ; регистры в стеке call find_files ; Вызываем процедуру поиска pop ecx ; Восстанавливаем pop eax ; регистры no_disk: ; Если диска нет, dec ecx ; то проверяем следующий jge find_drives ; пока ecx>0 invoke ExitProcess,0 ; Выходим из программы end start
Рекурсия в программировании - полный отстой - бесполезная трата тиков и замусоривание стека Везде в программах следует заменять рекурсию циклом Хотя в математике рекурся рулит, ну и ооочень редко может оказаться полезной где нибудь в специфических макросах.
Если задачу проще решить рекурсией - то я ее буду решать рекурсией, независимо от того, что говорит дядя Юров. Как пример - куда проще организовать поиск в субдиректориях через рекурсию, обход графа в глубину так же проще решается рекурсией, нежели через связанные списки. Y_Mur Часто лишние тики процессора позволяют сберечь уйму дополнительных стуков сердца и позволяет избежать замусоривания мозгов. Лишний часы моей жизни, сэкономленные на отладке - для меня это веский довод. Более того - грамотно организованная рекурсия никакого замусоривания не может вызвать в принципе.
nitrotoluol Вот и я о том же - хочешь сэкономить на отладке и улучшить читабельность программу всеми силами избегай рекурсий Рекурсия может сэкономить строки в хай-левел программе, но ценой ухудшения исполнимого кода и читабельности/понимаемости проги Ты в курсе что в твоём примере каждый самовызов добавляет в стек Code (Text): push ebp ; Выделим место в стеке mov ebp,esp ; под хэндл поиска sub esp,144h ; и структуру WIN32_FIND_DATA хотя реально тебе нужна только одна копия? Кроме того стек забивается одинаковыми адресами возврата, что в общем-то мелочь, но кроме стека адресами возврата забивается механизм предсказания возвратов (из которого вытесняются полезные адреса) а это уже аукнется при дальнейшем исполнении программы. А когда основной цикл рекурсии прокртится начнётся второй цикл основанный на ret-ах, в котором чистится тот хламник что накопился в основном цикле, конечно можно приспособить этот дополнительный цикл на что-то полезное, но проще обойтись без этого гемороя, правильно построив алгоритм
товарищи! вот здесь nitrotoluol привён код поиска файла. Он у меня почему то при ассемблировании выдаёт ошибку: ассемблирую: ml.exe dd.asm в итоге при линковании выдаётся ошибка:"fatal error L1104: \masm32\lib\user32.lib: not valid library" (это он про includelib \masm32\lib\user32.lib) подозреваю что то же он скажет и про includelib \masm32\lib\kernel32.lib объясните что такое происходит. спасибо.
просто вспомнилась фраза по поводу "Итерация подобна человеку, рекурсия - Богу" я тоже не против и за рекурсию, но обход файлов имхо лучше делать через неё, кстати за примером далеко ходить не нужно в стандартной поставке масм есть закоментированный экзапл называется findfile (хотя приведённый веше сорец тоже на первый взгляд неплох). Кстати имхо эта рекурсия в данном случае куда красивее смотрится на стандартных макросах .if/.endif с отодвиганием вложенного кода вправо как это принята в яву. Когда-то писал, но сорец кажется канул в лету