Вопрос № 183242: Здравствуйте, уважаемые эксперты! Прошу помощи в следующем вопросе: Необходимо разработать программу для поиска и удаления файлов по дате в заданном каталоге с подкаталогами. И ещё желательно сделать блок-схему по работе как процедур, так и пр...
Вопрос № 183242:
Здравствуйте, уважаемые эксперты! Прошу помощи в следующем вопросе:
Необходимо разработать программу для поиска и удаления файлов по дате в заданном каталоге с подкаталогами. И ещё желательно сделать блок-схему по работе как процедур, так и программы в целом.
Платформа: DOS, Тип ассемблера: TASM, Тип процессора: i8086. - вроде бы указал всё нужное.
Заранее спасибо.
Отправлен: 19.05.2011, 16:04
Вопрос задал: Денис (Посетитель)
Всего ответов: 1 Страница вопроса »
Отвечает Лысков Игорь Витальевич (Старший модератор) :
Здравствуйте, Денис! Вот и программа. Разберетесь?
Код :
.model tiny, pascal
;структура, необходимая для поиска
_DTA struc
bRes db 21 dup (?)
bAttr db ?
dwTime dw ?
dwDate dw ?
ddSize dd ?
bName db 13 dup (?)
bLast db ?
_DTA ends
.data
NCnt dw 0 ;счетчик найденных файлов
NOff dw 0 ;смещение для следующего имени
date dw 0 ;дата файла в спец формате
mm db '*.*',0 ;маска для поиска
sDir db 'Enter directory: $'
sDate db 0dh,0ah,'Enter date (dd.mm.yy): $'
sFound db 0dh,0ah,'Found $'
sFiles db ' files.$'
sDel db ' Delete ? (y,n)$'
sDel1 db 0dh, 0ah, 'Deleted $'
sAny db 0dh,0ah,'Press any key$'
;число дней в месяцах (для контроля правильности даты)
;учитывается високосный февраль
nDays db 31,28,31,30,31,30,31,31,30,31,30,31
;структура для ввода имены каталога
_name db 128
cntn db ?
dir db 128 dup (?)
;структура для ввода времени
_date db 11
cntd db ?
dated db 11 dup (?)
.code
.186
.startup
lea dx, sDir ;вводим каталог
mov ah, 9
int 21h
lea dx, _name
mov ah, 0ah
int 21h
xor bx, bx ;заменим последний код 0dh на 0
mov bl, cntn
mov byte ptr dir[bx], 0
repeat: ;цикл ввода правильной даты
lea dx, sDate ;вводим дату в виде dd.mm.yy
mov ah, 9 ;можно dd.mm и даже dd
int 21h
lea dx, _date
mov ah, 0ah
int 21h
;проверяем и конвертируем дату в спец формат
call ConvertDate, offset dated
jc repeat ;если ошибка, то на повтор
mov date, ax ;сохраним дату
;ищем файлы
call SearchDir, ax, offset dir
;удаляем
call Delete
PrintAny:
lea dx, sAny
mov ah, 9
int 21h
xor ax, ax
int 16h
mov ax, 4c00h
int 21h
;вывод на экран ASCII строки
PrintStr proc
lodsb
cmp al, 0
je PrintStrRet
int 29h
jmp PrintStr
PrintStrRet:
ret
PrintStr endp
;копирование ASCII строки strSrc в strDst
CopyStr proc strSrc:word, strDst:word
mov si, strSrc
mov di, strDst
CopyStrLoop:
lodsb
stosb
cmp al, 0
jne CopyStrLoop
ret
CopyStr endp
;удаление ранее найденных файлов
;с выдачей запроса
Delete proc
;выдача сообщения "Found NN files. Delete? (y,n)"
lea dx, sFound ;Found
mov ah, 9
int 21h
mov ax, NCnt ;NN
call PrintNum
lea dx, sFiles ;files
mov ah, 9
int 21h
cmp NCnt, 0 ;если ничего не найдего
je DelRet ;то нечего и удалять
lea dx, sDel ;Delete? (y,n)
mov ah, 9
int 21h
mov ah, 0 ;Ждем
int 16h
or al, 20h ;Превратим в маленькую буковку
cmp al, 'y'
jne DelRet ;не y - ничего не делаем
;удаляем
push ds ;перейдем в сегмент с именами
mov cx, NCnt ;количество имен
mov ax, ds
add ax, 1000h ;сегмент с именами
mov ds, ax ;ds для адреса имени
mov es, ax ;es для поиска следующего
xor di, di ;адрес имени
xor bx, bx ;счетчик удаленных
DeleteLoop: ;по всем именам
mov dx, di ;ds:dx адрес имени удаляемого файла
mov ah, 41h
int 21h ;удаляем!
jc DeleteNext
inc bx ;считаем реально удаленные
DeleteNext:
push cx ;найдем путь и имя следующего файла
mov al, 0
mov cx, 0ffffh
repne scasb ;ищем завершающий 0
pop cx
loop DeleteLoop ;по всем
pop ds ;востановим сегмент данных программы
lea dx, sDel1 ;сообщение Deleted
mov ah, 9
int 21h
mov ax, bx ;NN
call PrintNum
lea dx, sFiles ;files
mov ah, 9
int 21h
DelRet:
ret
Delete endp
;Рекурсивная процедура поиска файлов
;параметры: дата и путь к каталогу
SearchDir proc SDDate:word, SDPath:word
local dta:_DTA, olddta:word:2
local NextPath:byte:128
local PathPos:word
;скопируем путь в локальный буфер
lea ax, NextPath
call CopyStr, SDPath, ax
;добавим в конце слеш, если его нет
dec di
cmp byte ptr [di-1],':' ;после диска слеш не добавляем!
je SetLen
cmp byte ptr [di-1],'\'
je SetLen
mov word ptr [di], '\'
inc di
SetLen:
mov PathPos, di ;сохраним позицию, куда будем писать
call CopyStr, offset mm, di ;добавим маску *.*
push es ;сохраним адрес старой DTA
mov ah, 2fh
int 21h
mov olddta, bx
mov olddta+2, es
pop es
mov ah, 1ah ;установим новую DTA
lea dx, dta
int 21h
mov ah, 4Eh ;Ищем первый файл по маске
lea dx, NextPath ;путь с маской для поиска
mov cx, 10h ;ищем файлы с поддерикториями
mov di, SDDate ;дата, которую будем искать
DirLoop:
int 21h ;ищем первого/следующего
jc found_error ;ошибка?
push di ;сохраним дату
lea ax, dta.bName ;скопируем имя найденного файла/каталога
call CopyStr, ax, PathPos ;с позиции PathPos (за слешем)
pop di
test byte ptr dta.bAttr, 10h ;проверим атрибут - подкаталог?
jz FileFound ;нашли файл
;подкаталог
cmp word ptr dta.bName, '.' ;. и .. пропустим
je next
cmp word ptr dta.bName, '..'
je next
lea ax, NextPath
call SearchDir, di, ax ;ищем в поддиректории
jmp next
FileFound:
cmp dta.dwDate, di ;для файла сравниваем даты
jne next
push di es ;дата равна требуемой!
mov ax, ds ;сохраним путь с именем
add ax, 1000h ;в сегменте за программой
mov es, ax
lea ax, NextPath
call CopyStr, ax, NOff
mov NOff, di ;сохраним адрес для следующего имени
pop es di
inc NCnt ;считаем
mov al, 0dh ;выведем на экран
int 29h
mov al, 0ah
int 29h
lea si, NextPath
call PrintStr
next:
mov ah, 4Fh ; Ищем следующий
jmp DirLoop ; Продолжаем
found_error:
cmp ax, 12h ; ошибка 12h - завершение поиска
je finish
;здесь анализ всех остальных ошибок
;надо бы, для полноты картины, проанализироать,
;но можно убрать вообще все от found_error до finish (последнюю оставить)
finish:
push ds ;восстановим DTA
mov ah, 1ah
lds dx, dword ptr olddta
int 21h
pop ds
ret
SearchDir endp
;определение, является ли год nYear високосным
;параметры: ah - число дней в месяце,
;bh - месяц (1-12), в случае високосного
;года увеличиваем для февраля ah на 1
;алгоритм:
; 1. Год делится на 400 -> високосный -> конец
; 2. Год делится на 100 -> не високосный -> конец
; 3. Год делится на 4 -> високосный -> конец
; 4. Год не високосный -> конец
IsVisokosny proc nYear:word
cmp bh, 2
jne IVRet ;рассматриваем только 2 месяц
xor cx, cx ;добавка = 0
push ax
push dx
mov si, 400
mov ax, nYear
xor dx, dx
div si ;делим на 400
test dx, dx
jz VisokosnyYes ;нацело - високосный
mov si, 100
mov ax, nYear
xor dx, dx
div si ;делим на 100
test dx, dx
jz VisokosnyNo ;нацело - невисокосный
mov ax, nYear
test al, 3
jnz VisokosnyNo ;на 4 не делится - невисокосный
VisokosnyYes: ;високосный
inc cx ;добавка = 1
VisokosnyNo:
pop dx
pop ax
add ah, cl ;добавляем поправку
IVRet:
ret
IsVisokosny endp
;ввод числа (части даты)
GetNum proc
lodsb ;первый символ
sub al, '0'
jc GNErr ;< 0 - ошибка
cmp al, 9
ja GNErr ;> 9 - ошибка
mov dl, al ;сохраним
lodsb ;следующий символ
cmp al, 0dh
je GNRet ;конец строки - на выход
cmp al, '.'
je GNRet ;точка - на выход
sub al, '0'
jc GNErr ;< 0 - ошибка
cmp al, 9
ja GNErr ;> 9 - ошибка
xchg al, dl
mov ah, 10
mul ah
add dx, ax ;в dx день
lodsb ;следующий символ
cmp al, 0dh
je GNRet ;конец строки - на выход
cmp al, '.'
jne GNErr ;точка - на выход
GNRet:
clc ;все ок
ret
GNErr:
stc ;ошибка
ret
GetNum endp
;проверка даты на корректность
;bl - день, bh - месяц, dx - год
CmpDate proc
xor ax, ax
mov al, bh ;месяц
cmp al, 1
jl CmpDateErr
cmp al, 12
jg CmpDateErr ;должен быть [1,12]
cmp bl, 1
jl CmpDateErr ;день от 1 до максимального для месяца
mov si, ax ;месяц
mov ah, nDays[si-1] ;число дней в месяце
call IsVisokosny,dx ;поправка на високосный год
cmp bl, ah ;проверка на макс число
jg CmpDateErr
clc ;дата корректна
ret
CmpDateErr:
stc ;ошибка
ret
CmpDate endp
;конвертация даты в спец формат
;параметр - адрес строки с датой dd.mm.yy
ConvertDate proc pDate:word
mov si, pDate ;адрес строки
xor dx, dx ;обнулим на всякий случай
call GetNum ;день
jc CDErr ;ошибка?
mov bl, dl ;сохраним в bl
cmp al, 0dh ;конец строки?
je CDDay ;доформируем текущей датой
call GetNum ;месяц
jc CDErr ;ошибка?
mov bh, dl ;сохраним в bh
cmp al, 0dh ;конец строки?
je CDMonth ;доформируем текущей датой
call GetNum ;год
jc CDErr ;ошибка?
cmp al, 0dh ;если не конец строки
jne CDErr ;то ошибка!
add dx, 2000 ;добавим до года старшие разряды
CDCmpDate:
call CmpDate ;проверим на корректность
jc CDErr ;ошибка?
;сконвертируем в спец формат
sub dx, 1980 ;yyyyyyym mmmddddd - побитное содержимое полей
shl dx, 9
xor ax, ax
mov al, bh
shl ax, 5
or al, bl
or ax, dx
clc
ret
CDErr:
stc ;ошибка
ret
CDMonth:
mov ah, 2ah ;добавим текущий год
int 21h
mov dx, cx
jmp CDCmpDate ;на проверку
CDDay:
mov ah, 2ah ;добавим текущие месяц и год
int 21h
mov bh, dh
mov dx, cx
jmp CDCmpDate ;на проверку
ConvertDate endp
PrintNum proc ;вывод беззнакового числа из ax
push cx ;сохраним счетчик колонок
mov bx, 10 ;будем делить на 10
xor cx, cx ;счетчик цифр
DivLoop:
xor dx, dx ;готовимся к делению dx:ax / bx
div bx ;ax - частное, dx - остаток=очередной младшей цифре
push dx ;сохраним цифру в стеке
inc cx ;посчитаем
test ax, ax ;продолжим, пока не 0
jnz DivLoop
mov ah, 2 ;функция вывода
PrintLoop: ;будем выводить в обратном порядке, начиная со старшей шифры
pop ax ;восстановим очередной разряд
or al, '0' ;превратим в символ
int 29h ;выведем
loop PrintLoop
pop cx ;восстановим счетчик колонок матрицы
ret
PrintNum endp
end
----- Люби своего ближнего, как самого себя
Ответ отправил: Лысков Игорь Витальевич (Старший модератор)
Ответ отправлен: 22.05.2011, 23:09
Номер ответа: 267299 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru
Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"?
Отправить SMS#thank 267299
на номер 1151 (Россия) |
Еще номера »
Оценить выпуск »
Нам очень важно Ваше мнение об этом выпуске рассылки!
* Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи.
(полный список тарифов)
** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
*** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.