Всем привет. Подобные темы тут уже поднимались но все ж таки.
программирую под дос. задача составить программу поиска файла на диске. Нужно организовать поиска файлов во всех подкаталогах.
Сделанная програма: вложение test
В текущем каталоге производит поиск по маске.
Попытка организовать поиск в каталогах не удачная.
прошу подсказки как правильно организовать поиск в подпапках. Подскажите или детальный алгоритм или может есть где то листинг такой програмы.
Поиск файла
Модератор: Andy
-
- Сообщения: 3
- Зарегистрирован: 11 май 2011, 00:51
- Откуда: Кировоград
- Контактная информация:
-
- Сообщения: 3
- Зарегистрирован: 11 май 2011, 00:51
- Откуда: Кировоград
- Контактная информация:
.MODEL small
LOCALS ;директива LOCAL нужна дял объявления локальный переменных v процедурах
PathLen = 100 ; Максимальный путь к файлу/каталогу
; (уменьшать это значение нежелательно)
Data segment
startmsg db 'Внимание! Программа корректно работает в среде Ms-DOS или эмуляторе!',13,10,'$'
dta db 256 dup(?) ;буфер для размещения инфы про файлы
errormsg db '__________Поиск окончен!!!__________',13,10,'$'
startmsg1 db 'Введите маску поиска (пример: 1.txt): $'
buffer db 25 ;макс длина маски поиска
dlina db 0 ; фактическая длина ввода
fmask db 25 DUP (?),13,10,'$' ;тут маска ввода
; ScanMask db '*.*',0 ; Маска каталогов для поиска
StartPath db 'D:\',0 ; Стартовый каталог
ORG StartPath ; Совмещаем StartPath и ScanPath
ScanPath db PathLen dup (?) ; ASCIIZ-имя найденного каталога
crlf db 13,10,'$'
FCatNm db 8 dup (0)
FCatNmP dw 0
data ends
SSEG SEGMENT STACK
DB 200 DUP(?)
SSEG ENDS
CODE segment
assume cs:code, ds:data, ss:sseg
begin:
mov ax,data
mov ds,ax
;устанавливаем буфер DTA
mov ah,1ah
lea dx,dta
int 21h
;=====очистка екрана========
mov ah,0 ;очистка экрана
mov al,2
int 10h
;=====вывод сообщения======
mov ah,09h
mov dx,offset startmsg
int 21h
;=====вывод сообщения2======
mov ah,09h
mov dx,offset startmsg1
int 21h
call input_mask
;=== Маски атрибутов файлов/каталогов===
faReadOnly = 1
faHidden = 2
faSystem = 4
faVolume = 8
faDirectory = 10h ;010h
faArchive = 20h ;020h
faAnyFile = faReadOnly+faHidden+faSystem+faArchive ;03fh
faAnyDir = faAnyFile+faDirectory
faAnithing = faAnyDir+faVolume
;===================================
call N_K ; курсор на новую строку
;push offset MyFunc
call find_f ; вызов процедуры поиска первого файла
call out_name
cmp ax,12h ;проверка есть ли каталоги
jne Fcat
jc exit ; нет файлов-выход
Fcat: mov si,offset DTA + 30 ;в si смещение имени найденного каталога
mov FCatNmP,si
mov bx,FCatNmP
mov al,[bx]
cmp al,2eh ;не является ли . или .. именем
je exit
; call SaveIndx ;сохранение индекса для дальнейшего поиска
; call SearchInto ;поиск в найденном
; call LoadIndx ;восстановления индекса
dir:
call find_n
jc exit
;======выводим имя====
call out_name
jmp short dir
;===== ==конец=====
exit:
mov ah,09h
mov dx,offset errormsg
int 21h
mov ah,4ch
int 21h
;=========процедура ввода с клавиатуры===============
Input_mask Proc ;процедура ввода с клавиатуры
mov ah,0Ah ;
mov dx,offset buffer
int 21h
inc dx ;адрес буфера ввода +1, dx указывает на dlina - ;кол-во введенных символов
mov di,dx ; di=dx адрес переменной длина
mov bl,[di] ; кол-во введенных символов, bl=dlina
mov [di],ah ; записать ah по адресу находящемуся в di, dlina=ah
xor bh,bh ;Можно и без этого, но! лучше так.
inc di ;di=di+1 теперь di содержит адрес начала строки text
mov byte ptr [di+bx],'$' ; записать в конец строки знак доллар
ret
Input_mask endp
;=======процедура поиска первого=======
find_f proc
lea dx,fmask
mov ah,4eh
mov cx,faAnyDir ;в сх поиск без скрытых и меток тома
;проверяем найден ли каталог
; test DTA.010h,faDirectory
; jnz ScanTree ;если каталог тогда вызов скан три
;jz ScanTree
int 21h
ret
find_f endp
;====процедура поиска следующего======
find_n proc
; lea dx,dta
mov ah,4fh
int 21h
ret
find_n endp
;============Функция обработки строки имени каталога=====
MyFunc proc
lea di,ScanPath ; DI = адрес строки ScanPath
push di
mov cx,PathLen
xor al,al
repne scasb ; Ищем конец строки
dec di
mov word ptr [di],0A0Dh ; Записываем туда CR,LF...
mov byte ptr [di+2],'$' ; ...и символ доллара (для ф-ии 9)
mov ah,9
pop dx
int 21h ; Выводим строку на экран
mov byte ptr [di],0; Восстанавливаем строку ScanPath
; (т.к. изменять ее нельзя)
ret
MyFunc endp
;====перевод курсора на новую строку====
N_K proc
push dx
push ax
mov ah,2
mov dl,13 ; CR (курсор на начало строки)
int 21h
mov dl,10 ; LF (курсор на следующую строку)
int 21h
pop ax
pop dx
ret
N_K endp
;======процедура вывода имени===========
;======с буфера дта по смещению 1еh=======
out_name proc
mov bx,1eh
mov ah,2
out_s:
mov dl,[dta+bx]
cmp dl,0
jz kon
int 21h
inc bx
jmp short out_s
kon:
;перевод строки
mov dl,13
int 21h
mov dl,10
int 21h
ret
out_name endp
;======структура нового буфера DTA====
DTAFileInfo struc
dtaReserved db 21 dup (?)
dtaAttr db ?
dtaTime dw ?
dtaDate dw ?
dtaSize dd ?
dtaName db 13 dup (?)
ends
*********
LOCALS ;директива LOCAL нужна дял объявления локальный переменных v процедурах
PathLen = 100 ; Максимальный путь к файлу/каталогу
; (уменьшать это значение нежелательно)
Data segment
startmsg db 'Внимание! Программа корректно работает в среде Ms-DOS или эмуляторе!',13,10,'$'
dta db 256 dup(?) ;буфер для размещения инфы про файлы
errormsg db '__________Поиск окончен!!!__________',13,10,'$'
startmsg1 db 'Введите маску поиска (пример: 1.txt): $'
buffer db 25 ;макс длина маски поиска
dlina db 0 ; фактическая длина ввода
fmask db 25 DUP (?),13,10,'$' ;тут маска ввода
; ScanMask db '*.*',0 ; Маска каталогов для поиска
StartPath db 'D:\',0 ; Стартовый каталог
ORG StartPath ; Совмещаем StartPath и ScanPath
ScanPath db PathLen dup (?) ; ASCIIZ-имя найденного каталога
crlf db 13,10,'$'
FCatNm db 8 dup (0)
FCatNmP dw 0
data ends
SSEG SEGMENT STACK
DB 200 DUP(?)
SSEG ENDS
CODE segment
assume cs:code, ds:data, ss:sseg
begin:
mov ax,data
mov ds,ax
;устанавливаем буфер DTA
mov ah,1ah
lea dx,dta
int 21h
;=====очистка екрана========
mov ah,0 ;очистка экрана
mov al,2
int 10h
;=====вывод сообщения======
mov ah,09h
mov dx,offset startmsg
int 21h
;=====вывод сообщения2======
mov ah,09h
mov dx,offset startmsg1
int 21h
call input_mask
;=== Маски атрибутов файлов/каталогов===
faReadOnly = 1
faHidden = 2
faSystem = 4
faVolume = 8
faDirectory = 10h ;010h
faArchive = 20h ;020h
faAnyFile = faReadOnly+faHidden+faSystem+faArchive ;03fh
faAnyDir = faAnyFile+faDirectory
faAnithing = faAnyDir+faVolume
;===================================
call N_K ; курсор на новую строку
;push offset MyFunc
call find_f ; вызов процедуры поиска первого файла
call out_name
cmp ax,12h ;проверка есть ли каталоги
jne Fcat
jc exit ; нет файлов-выход
Fcat: mov si,offset DTA + 30 ;в si смещение имени найденного каталога
mov FCatNmP,si
mov bx,FCatNmP
mov al,[bx]
cmp al,2eh ;не является ли . или .. именем
je exit
; call SaveIndx ;сохранение индекса для дальнейшего поиска
; call SearchInto ;поиск в найденном
; call LoadIndx ;восстановления индекса
dir:
call find_n
jc exit
;======выводим имя====
call out_name
jmp short dir
;===== ==конец=====
exit:
mov ah,09h
mov dx,offset errormsg
int 21h
mov ah,4ch
int 21h
;=========процедура ввода с клавиатуры===============
Input_mask Proc ;процедура ввода с клавиатуры
mov ah,0Ah ;
mov dx,offset buffer
int 21h
inc dx ;адрес буфера ввода +1, dx указывает на dlina - ;кол-во введенных символов
mov di,dx ; di=dx адрес переменной длина
mov bl,[di] ; кол-во введенных символов, bl=dlina
mov [di],ah ; записать ah по адресу находящемуся в di, dlina=ah
xor bh,bh ;Можно и без этого, но! лучше так.
inc di ;di=di+1 теперь di содержит адрес начала строки text
mov byte ptr [di+bx],'$' ; записать в конец строки знак доллар
ret
Input_mask endp
;=======процедура поиска первого=======
find_f proc
lea dx,fmask
mov ah,4eh
mov cx,faAnyDir ;в сх поиск без скрытых и меток тома
;проверяем найден ли каталог
; test DTA.010h,faDirectory
; jnz ScanTree ;если каталог тогда вызов скан три
;jz ScanTree
int 21h
ret
find_f endp
;====процедура поиска следующего======
find_n proc
; lea dx,dta
mov ah,4fh
int 21h
ret
find_n endp
;============Функция обработки строки имени каталога=====
MyFunc proc
lea di,ScanPath ; DI = адрес строки ScanPath
push di
mov cx,PathLen
xor al,al
repne scasb ; Ищем конец строки
dec di
mov word ptr [di],0A0Dh ; Записываем туда CR,LF...
mov byte ptr [di+2],'$' ; ...и символ доллара (для ф-ии 9)
mov ah,9
pop dx
int 21h ; Выводим строку на экран
mov byte ptr [di],0; Восстанавливаем строку ScanPath
; (т.к. изменять ее нельзя)
ret
MyFunc endp
;====перевод курсора на новую строку====
N_K proc
push dx
push ax
mov ah,2
mov dl,13 ; CR (курсор на начало строки)
int 21h
mov dl,10 ; LF (курсор на следующую строку)
int 21h
pop ax
pop dx
ret
N_K endp
;======процедура вывода имени===========
;======с буфера дта по смещению 1еh=======
out_name proc
mov bx,1eh
mov ah,2
out_s:
mov dl,[dta+bx]
cmp dl,0
jz kon
int 21h
inc bx
jmp short out_s
kon:
;перевод строки
mov dl,13
int 21h
mov dl,10
int 21h
ret
out_name endp
;======структура нового буфера DTA====
DTAFileInfo struc
dtaReserved db 21 dup (?)
dtaAttr db ?
dtaTime dw ?
dtaDate dw ?
dtaSize dd ?
dtaName db 13 dup (?)
ends
*********
-
- Сообщения: 3
- Зарегистрирован: 11 май 2011, 00:51
- Откуда: Кировоград
- Контактная информация:
***********
; Процедура обхода всех подкаталогов заданного каталога.
; Процедура может работать и в программах формата DOS EXE !!!
; На входе:
; - Переменная StartPath (она же ScanPath) содержит имя стартового каталога.
; Имя каталога должно заканчиваться обратным слэшем ('\') !
; - В стеке смещение (word) near-функции, которая будет вызываться для каждого
; найденного каталога. При этом она может использовать ASCIIZ-строку ScanPath,
; которая содержит полное имя найденного каталога со слэшем на конце, но не
; должна изменять эту строку! При необходимости функция должна скопировать
; строку в какой-нибудь буфер, где может делать с ней все, что нужно
; Функция также не должна использовать установленный DTA, при необходимости
; нужно создать свой буфер DTA. Адрес прежнего буфера восстанавливать при
; выходе не нужно, как и регистры DS, ES, если они были изменены.
; На выходе:
; - DTA и регистры DS,BP сохранены.
; - Строка StartPath/ScanPath содержит полное имя последнего найденного каталога.
; - ES
I указывает на конец строки StartPath/ScanPath, которая была при вызове
; функции (т.е. можно сделать xor al,al / stosb и снова вызвать ScanTree).
ScanTree proc pascal
arg Func:word
local OldDTA:dword, NewDTA
TAFileInfo
; ES всегда равно первоначальному DS !!!
push ds ; Сохраняем DS
mov ah,2Fh ;адрес текущей DTA
int 21h ; Получаем адрес DTA
mov word ptr OldDTA[0],bx ; Сохраняем его...
mov word ptr OldDTA[2],es ; ...в переменной OldDTA
pop es ; Восстанавливаем DS в регистр ES (ES=DS)
lea di,ScanPath
mov cx,PathLen
xor al,al
cld ; Прямой порядок поиска scasb
repne scasb ; Ищем в имени каталога нулевой байт (конец строки)
dec di
push di ; Сохраняем указатель на ноль
push ds es ; Сохраняем DS и ES
call Func ; Вызываем функцию для стартового каталога
mov ah,1Ah
push ss
pop ds ; DS = SS (сегмент NewDTA)
lea dx,NewDTA
int 21h ; Устанавливаем свой DTA
pop es ds ; Восстанавливаем DS и ES (ES=DS)
mov ah,4Eh ; Готовимся в началу поиска
mov cx,faAnyDir ; Атрибуты (все, кроме Volume label)
lea dx,ScanPath
lea si,fMask ; SI = адрес макси поиска
; lea si,ScanMask ; SI = адрес макси поиска
pop di ; Восстанавливаем DI (указатель на конец строки)...
push di ; ...и тут же сохраняем его
cld ; Прямой порядок работы lodsb/stosb
@@CopyMask: lodsb ; Читаем в AL символ из строки [SI]
stosb ; И записываем его в конец ScanPath
or al,al ; Конец строки [SI] (AL=0) ?
jnz @@CopyMask ; Нет, копируем следующий символ
@@FindNext:
int 21h ; Начинаем/продолжаем поиск
jc @@NotFound ; Выходим, если ничего не найдено (CF=1)
push ss
pop ds ; DS = SS (сегмент NewDTA)
test NewDTA.dtaAttr,faDirectory ; Проверяем - каталог ли был найден
jz @@NotFound ; Если нет, выход
; jz @@PrepareNext ; Если нет, готовимся продолжать поиск
lea si,NewDTA.dtaName ; Адрес имени найденного файла/каталога
lodsb ; Читаем первый символ
cmp al,'.' ; Это каталоги '.' и '..'? (нам такие не нужны)
je @@PrepareNext ; Если это они, готовимся продолжать поиск
pop di ; Восстанавливаем DI (указатель на конец строки)...
push di ; ...и тут же сохраняем его
@@CopyPath:
stosb ; Записываем символ строки [SI] в конец ScanPath
lodsb ; Читаем в AL символ из строки [SI]
or al,al ; Конец строки [SI] (AL=0) ?
jnz @@CopyPath ; Нет, копируем следующий символ
mov ax,'\' ; AH = 0, AL = '\'
stosw ; Записываем слэш и ноль в конец строки
push es
pop ds ; DS = ES
push Func
call ScanTree ; Вызываем себя рекурсивно
push ss
pop ds ; DS = SS (сегмент NewDTA)
@@PrepareNext:
mov ah,4Fh ; Готовимся к функции 4Fh
lea dx,NewDTA
jmp @@FindNext ; Продолжаем поиск
@@NotFound:
pop di ; Убираем из стека DI
mov ah,1Ah
lds dx,OldDTA
int 21h ; Восстанавливаем DTA
push es
pop ds ; Восстанавливаем первоначальный DS
ret ; Выходим из процедуры
ScanTree endp
code ends
end begin
моя програма. Выложил текстом так как прикрепить вложение не получается. (((
; Процедура обхода всех подкаталогов заданного каталога.
; Процедура может работать и в программах формата DOS EXE !!!
; На входе:
; - Переменная StartPath (она же ScanPath) содержит имя стартового каталога.
; Имя каталога должно заканчиваться обратным слэшем ('\') !
; - В стеке смещение (word) near-функции, которая будет вызываться для каждого
; найденного каталога. При этом она может использовать ASCIIZ-строку ScanPath,
; которая содержит полное имя найденного каталога со слэшем на конце, но не
; должна изменять эту строку! При необходимости функция должна скопировать
; строку в какой-нибудь буфер, где может делать с ней все, что нужно

; Функция также не должна использовать установленный DTA, при необходимости
; нужно создать свой буфер DTA. Адрес прежнего буфера восстанавливать при
; выходе не нужно, как и регистры DS, ES, если они были изменены.
; На выходе:
; - DTA и регистры DS,BP сохранены.
; - Строка StartPath/ScanPath содержит полное имя последнего найденного каталога.
; - ES

; функции (т.е. можно сделать xor al,al / stosb и снова вызвать ScanTree).
ScanTree proc pascal
arg Func:word
local OldDTA:dword, NewDTA

; ES всегда равно первоначальному DS !!!
push ds ; Сохраняем DS
mov ah,2Fh ;адрес текущей DTA
int 21h ; Получаем адрес DTA
mov word ptr OldDTA[0],bx ; Сохраняем его...
mov word ptr OldDTA[2],es ; ...в переменной OldDTA
pop es ; Восстанавливаем DS в регистр ES (ES=DS)
lea di,ScanPath
mov cx,PathLen
xor al,al
cld ; Прямой порядок поиска scasb
repne scasb ; Ищем в имени каталога нулевой байт (конец строки)
dec di
push di ; Сохраняем указатель на ноль
push ds es ; Сохраняем DS и ES
call Func ; Вызываем функцию для стартового каталога
mov ah,1Ah
push ss
pop ds ; DS = SS (сегмент NewDTA)
lea dx,NewDTA
int 21h ; Устанавливаем свой DTA
pop es ds ; Восстанавливаем DS и ES (ES=DS)
mov ah,4Eh ; Готовимся в началу поиска
mov cx,faAnyDir ; Атрибуты (все, кроме Volume label)
lea dx,ScanPath
lea si,fMask ; SI = адрес макси поиска
; lea si,ScanMask ; SI = адрес макси поиска
pop di ; Восстанавливаем DI (указатель на конец строки)...
push di ; ...и тут же сохраняем его
cld ; Прямой порядок работы lodsb/stosb
@@CopyMask: lodsb ; Читаем в AL символ из строки [SI]
stosb ; И записываем его в конец ScanPath
or al,al ; Конец строки [SI] (AL=0) ?
jnz @@CopyMask ; Нет, копируем следующий символ
@@FindNext:
int 21h ; Начинаем/продолжаем поиск
jc @@NotFound ; Выходим, если ничего не найдено (CF=1)
push ss
pop ds ; DS = SS (сегмент NewDTA)
test NewDTA.dtaAttr,faDirectory ; Проверяем - каталог ли был найден
jz @@NotFound ; Если нет, выход
; jz @@PrepareNext ; Если нет, готовимся продолжать поиск
lea si,NewDTA.dtaName ; Адрес имени найденного файла/каталога
lodsb ; Читаем первый символ
cmp al,'.' ; Это каталоги '.' и '..'? (нам такие не нужны)
je @@PrepareNext ; Если это они, готовимся продолжать поиск
pop di ; Восстанавливаем DI (указатель на конец строки)...
push di ; ...и тут же сохраняем его
@@CopyPath:
stosb ; Записываем символ строки [SI] в конец ScanPath
lodsb ; Читаем в AL символ из строки [SI]
or al,al ; Конец строки [SI] (AL=0) ?
jnz @@CopyPath ; Нет, копируем следующий символ
mov ax,'\' ; AH = 0, AL = '\'
stosw ; Записываем слэш и ноль в конец строки
push es
pop ds ; DS = ES
push Func
call ScanTree ; Вызываем себя рекурсивно
push ss
pop ds ; DS = SS (сегмент NewDTA)
@@PrepareNext:
mov ah,4Fh ; Готовимся к функции 4Fh
lea dx,NewDTA
jmp @@FindNext ; Продолжаем поиск
@@NotFound:
pop di ; Убираем из стека DI
mov ah,1Ah
lds dx,OldDTA
int 21h ; Восстанавливаем DTA
push es
pop ds ; Восстанавливаем первоначальный DS
ret ; Выходим из процедуры
ScanTree endp
code ends
end begin
моя програма. Выложил текстом так как прикрепить вложение не получается. (((