Поиск файлов
Поиск файлов.
Для поиска файлов в Windows существуют две функции FindFirstFile и FindNextFile, очень похожие на аналогичные функции MS DOS и, как и там, работающие в паре. При успешном поиске первая функция возвращает некое число или идентификатор, который затем используется второй функцией для продолжения поиска.
Первым параметром функции FindFirstFile является указатель на строку для поиска файлов, второй параметр - указатель на структуру, которая получает информацию о найденных файлах. Функция FindNextFile первым своим параметром имеет идентификатор, полученный первой функцией, а вторым параметром - указатель на структуру. Эту структуру можно изучить по программе на Рисунок 2.5.1.
Основным отличием этих функций от соответствующих функций MS DOS является то, что поиск ограничивается только маской поиска (*.*, *.ЕХЕ и т.п.). Если файл найден, то тогда по возвращаемой структуре, где содержится вся информация о нем, Вы уже можете решать, подходит файл или нет.
На Рисунок 2.5.1 представлена программа, осуществляющая поиск файлов в указанном каталоге. Программа может иметь один или два параметра, или не иметь их вовсе. Если имеются два параметра, то первый параметр трактуется как каталог для поиска, причем программа учитывает, есть ли на конце косая черта или нет (допустимо c:, c:\, c:\windows\, c:\windows\system и т.п.). Второй параметр (в программе он третий, так как первым считается командная строка), если он есть, представляет собой маску поиска. Если его нет, то маска поиска берется в виде "*.*". Наконец, если параметров нет вообще, то поиск осуществляется в текущем каталоге по маске "*.*". Эту программу легко развить и сделать из нее полезную утилиту. Предоставляю это Вам, дорогой читатель. Ниже будет дан комментарий к означенной программе.
; файл FILES.ASM .386P ; плоская модель .MODEL FLAT, stdcall ; константы STD_OUTPUT_HANDLE equ -11 STD_INPUT_HANDLE equ -10 ; прототипы внешних процедур EXTERN wsprintfA:NEAR EXTERN CharToOemA@8:NEAR EXTERN GetStdHandle@4:NEAR EXTERN WriteConsoleA@20:NEAR EXTERN ReadConsoleA@20:NEAR EXTERN ExitProcess@4:NEAR EXTERN GetCommandLineA@0:NEAR EXTERN lstrcatA@8:NEAR EXTERN FindFirstFileA@8:NEAR EXTERN FindNextFileA@8:NEAR EXTERN FindClose@4:NEAR ;----------------------------- ; структура, используемая для поиска файла ; при помощи функций FindFirstFile и FindNextFile _FIND STRUC ; атрибут файла ATR DWORD ? ; время создания файла CRTIME DWORD ? DWORD ? ; время доступа к файлу ACTIME DWORD ? DWORD ? ; время модификации файла WRTIME DWORD ? DWORD ? ; размер файла SIZEH DWORD ? SIZEL DWORD ? ; резерв DWORD ? DWORD ? ; длинное имя файла NAM DB 260 DUP (0) ; короткое имя файла ANAM DB 14 DUP(0) _FIND ENDS ;------------------------------------------------- ; директивы компоновщику для подключения библиотек includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ;-------------------------------------------------
; сегмент данных _DATA SEGMENT DWORD PUBLIC USE32 'DATA' BUF DB 0 DB 100 dup(0) LENS DWORD ? ; количество выведенных символов HANDL DWORD ? HANDL1 DWORD ? MASKA DB "*.*",0 АР DB "\",0 FIN _FIND <0> TEXT DB "Для продолжения нажмите клавишу ENTER",13,10,0 BUFIN DB 10 DUP(0) FINDH DWORD ? NUM DB 0 NUMF DWORD 0 ; счетчик файлов NUMD DWORD 0 ; счетчик каталогов FORM DB "Число найденных файлов: %lu",0 FORM1 DB "Число найденных каталогов: %lu",0 BUFER DB 100 DUP (?) DIR DB "<DIR>",0 PAR DB 0 ; количество параметров _DATA ENDS
; сегмент кода _TEXT SEGMENT DWORD PUBLIC USE32 'CODE' START: ; получить HANDLE вывода PUSH STD_OUTPUT_HANDLE CALL GetStdHandle@4 MOV HANDL,EAX ; получить HANDL1 ввода PUSH STD_INPUT_HANDLE CALL GetStdHandle@4 MOV HANDL1,EAX ; преобразовать строки для вывода PUSH OFFSET TEXT PUSH OFFSET TEXT CALL CharToOemA@8 PUSH OFFSET FORM PUSH OFFSET FORM CALL CharToOemA@8 PUSH OFFSET FORM1 PUSH OFFSET FORM1 CALL CharToOemA@8 ; получить количество параметров CALL NUMPAR MOV PAR,EAX ; если параметр один, то искать в текущем каталоге CMP EAX, 1 JE NO_PAR ;------------------------------------------------- ; получить параметр номером EDI MOV EDI, 2 LEA EBX,BUF CALL GETPAR PUSH OFFSET BUF CALL LENSTR ; если в конце нет "\" - добавим CMP BYTE PTR [BUF+EBX-1],"\" JE NO_PAR PUSH OFFSET AP PUSH OFFSET BUF CALL lstrcatA@8 ; нет ли еще параметра, где задана маска поиска CMP PAR,3 JB NO_PAR ; получить параметр - маску поиска MOV EDI,3 LEA EBX,MASKA CALL GETPAR NO_PAR: ;------------------------------------------------- CALL FIND ; вывести количество файлов PUSH NUMF PUSH OFFSET FORM PUSH OFFSET BUFER CALL wsprintfA LEA EAX, BUFER MOV EDX,1 CALL WRITE ; вывести количество каталогов PUSH NUMD PUSH OFFSET FORM1 PUSH OFFSET BUFER CALL wsprintfA LEA EAX, BUFER MOV EDX, 1 CALL WRITE _END: PUSH 0 CALL ExitProcess@4 ;************************ ; область процедур ;************************ ; вывести строку (в конце перевод строки) ; EAX - на начало строки ; EDX - с переводом строки или без WRITE PROC ; получить длину параметра PUSH EAX CALL LENSTR MOV ESI,EAX CMP EDX,1 JNE NO_ENT ; в конце - перевод строки MOV BYTE PTR [EBX+ESI],13 MOV BYTE PTR [EBX+ESI+1],10 MOV BYTE PTR [EBX+ESI+2],0 ADD EBX,2 NO_ENT: ; вывод строки PUSH 0 PUSH OFFSET LENS PUSH EBX PUSH EAX PUSH HANDL CALL WriteConsoleA@20 RET WRITE ENDP
; процедура определения длины строки ; строка - [EBP+08Н] ; длина в EBX LENSTR PROC PUSH EBP MOV EBP,ESP PUSH EAX ;---------------------- CLD MOV EDI, DWORD PTR [EBP+08Н] MOV EBX, EDI MOV ECX,100 ; ограничить длину строки XOR AL,AL REPNE SCASB ; найти символ 0 SUB EDI, EBX ;-длина строки, включая 0 MOV EBX, EDI DEC EBX ;---------------------- POP EAX POP EBP RET 4 LENSTR ENDP
; процедура определения количества параметров в строке ; определить количество параметров (->EAX) NUMPAR PROC CALL GetCommandLineA@0 MOV ESI,EAX ; указатель на строку XOR ECX,ECX ; счетчик MOV EDX,1 ; признак L1: CMP BYTE PTR [ESI],0 JE L4 CMP BYTE PTR [ESI],32 JE L3 ADD ECX,EDX ; номер параметра MOV EDX, 0 JMP L2 L3: OR EDX,1 L2: INC ESI JMP L1 L4: MOV EAX,ECX RET NUMPAR ENDP
; получить параметр из командной строки ; EBX - указывает на буфер, куда будет помещен параметр ; в буфер помещается строка с нулем на конце ; EDI - номер параметра GETPAR PROC CALL GetCommandLineA@0 MOV ESI, EAX ; указатель на строку XOR ECX, ECX ; счетчик MOV EDX, 1 ; признак L1: CMP BYTE PTR [ESI], 0 JE L4 CMP BYTE PTR [ESI], 32 JE L3 ADD ECX,EDX ; номер параметра MOV EDX,0 JMP L2 L3: OR EDX,1 L2: CMP ECX,EDI JNE L5 MOV AL,BYTE PTR [ESI] MOV BYTE PTR [EBX],AL INC EBX L5: INC ESI JMP L1 L4: MOV BYTE PTR [EBX], 0 RET GETPAR ENDP
; поиск в каталоге файлов и их вывод ; имя каталога в BUF FIND PROC ; путь с маской PUSH OFFSET MASKA PUSH OFFSET BUF CALL lstrcatA@8 ; здесь начало поиска PUSH OFFSET FIN PUSH OFFSET BUF CALL FindFirstFileA@8 CMP EAX,-1 JE _ERR ; сохранить дескриптор поиска MOV FINDH,EAX LF: ; исключить "файлы" "." и ".." CMP BYTE PTR FIN.NAM,"." JE _NO ; не каталог ли? TEST BYTE PTR FIN.ATR,10H JE NO_DIR PUSH OFFSET DIR PUSH OFFSET FIN.NAM CALL lstrcatA@8 INC NUMD DEC NUMF NO_DIR: ; преобразовать строку PUSH OFFSET FIN.NAM PUSH OFFSET FIN.NAM CALL CharToOemA@8 ; здесь вывод результата LEA EAX, FIN.NAM MOV EDX,1 CALL WRITE ; увеличить счетчики INC NUMF INC NUM ; конец страницы? CMP NUM, 22 JNE _NO MOV NUM, 0 ; ждать ввод строки MOV EDX,0 LEA EAX, TEXT CALL WRITE PUSH 0 PUSH OFFSET LENS PUSH 10 PUSH OFFSET BUFIN PUSH HANDL1 CALL ReadConsoleA@20 _NO: ; продолжение поиска PUSH OFFSET FIN PUSH FINDH CALL FindNextFileA@8 CMP EAX,0 JNE LF ; закрыть поиск PUSH FINDH CALL FindClose@4 _ERR: RET FIND ENDP _TEXT ENDS END START