Вопрос № 183472: Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос: помогите ,пожалуйста , написать программу, сообщающую о количестве строк в файле. Имя файла ввести с клавиатуры или передать как параметр командной строки. Чтение из файла орга...
Вопрос № 183472:
Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос: помогите ,пожалуйста , написать программу, сообщающую о количестве строк в файле. Имя файла ввести с клавиатуры или передать как параметр командной строки. Чтение из файла организовать блоком. Размер блока- по усмотрению. Желательны подробные комментарии. АСС-TASM. Заранее спасибо, с уважением Дмитрий.
Отвечает Лысков Игорь Витальевич (Старший модератор) :
Здравствуйте, Дмитрий! Для подсчета строк ищем и считаем код 0ah. Учитываем случай, когда в последней строке может и не быть кода 0ah. Программа сначала ищет имя файла, как параметр в командной строке, если не находит, то по запросу.
Код :
.model small
.stack 100h
.code
start:
mov ax, @data
mov es, ax ;настроим пока только регистр es
;ds равен сегменту PSP, там параметр командной строки
call GetParm ;смотрим параметр из командной строки, если есть,
;то dx - смещение имени файла в сегменте данных
mov ax, @data
mov ds, ax ;настроим и ds
jnc openFile ;если задано, то на открытие файла
;не задано - запрашиваем
lea dx, sGetIn ;строка приглашения 'Enter file name:'
call GetName ;ds:dx = адрес имени входного файла
;откроем входной файл
openFile:
mov ax, 3d00h ;открываем файл на чтение
int 21h
jc OpenError ;ошибка?
mov bx, ax ;сохраним описатель файла в bx для дальнейшей работы
xor si, si ;счетчик строк
lea dx, buffer ;адрес буфера
xor di, di ;для контроля файла 0 длины
;прочитаем
readLoop:
mov cx, 1000h ;будем читать 4к за 1 раз
mov ah, 3fh ;функция чтения
int 21h
jc ReadError ;ошибка?
mov cx, ax ;сохраним длину файла в cx
jcxz lastRow ;чтение после конца даст 0 - признак, что все прочитано
call CalcRows ;считаем строки кусочка
jmp readLoop ;и на повтор
lastRow: ;все прочитано, проверим случай, когда последняя строка
; не заканчивается на 0dh,0ah
test di, di ;если файл был 0 длины, то di останется = 0, иначе
jz printRows ; di содержит адрес за последним проанализированным куском
cmp byte ptr [di-1], 0ah ;вот и проверим последний байт на 0ah
je printRows ;равно - все учтено!
inc si ;нет - учтем последнюю строку без кода конца строки!
printRows:
lea dx, sRows ;выведем сообщение
mov ah, 9
int 21h
mov ax, si ;число строк
call PrintNum
closeFile:
mov ah, 3eh ;закроем входной файл
int 21h
PressAny:
lea dx, sAny ;выведем 'Press any key'
mov ah, 9
int 21h
mov ah, 0 ; ждем нажатие на клавишу
int 16h
mov ax,4c00h ; конец работы
int 21h
;обработка ошибок
OpenError: ;ошибка открытия (файл или не найден, или занят)
lea dx, sOpenErr
mov ah, 9
int 21h
jmp PressAny ;на вывод 'Press any key'
ReadError: ;ошибка чтения
lea dx, sReadErr
mov ah, 9
int 21h
jmp closeFile ;на закрытие и вывод 'Press any key'
CalcRows proc ;подсчет строк, dx - адрес буфера, cx - длина, результат - si
mov di, dx ;адрес начала буфера
mov al, 0ah ;будем искать код 0ah
calcLoop:
jcxz calcRet ;длина 0 - нечего делать
repne scasb ;ищем, пока не равно
jne calcRet ;не равно, значит дошли до конца
inc si ;равно - считаем
jmp calcLoop ;по всему буферу
calcRet:
ret
CalcRows endp
;Подпрограмма ввода имени файла
;на входе: ds:dx - адрес сообщения
;на выходе: ds:dx - адрес имени
GetName proc
mov ah, 9 ;выведем приглашение из dx:dx
int 21h
lea dx, buf ;введем строку
mov ah, 0ah
int 21h
xor bx, bx ;заменим последний код 0dh на 0
mov bl, len ;длина введенной строки
mov byte ptr string[bx], 0 ;пишем 0
lea dx, string ;возвращаем адрес имени
ret
GetName endp
;анализ параметра
;адрес параметра в PSP находится по адресу PSP:80h - длина, PSP:81h - сам параметр,
;заканчивающийся кодом 0dh. Мы длину трогать не будем, а будем анализировать по коду 0dh
;имя файла можно как предворять, так и завершать разделителями (пробелом, табуляцией)
;флагом CF = 0/1 вернем результат: задано/не задано имя файла
GetParm proc
mov si, 81h ;параметр в сегменте PSP
lea di, string ;адрес в сегменте данных, куда запишем имя файла
mov dx, di ;здесь вернем адрес имени, если задано, конечно
xor cx, cx ;счетчик символов имени файла
parmLoop:
lodsb ;очередной
cmp al, 0dh
je endParm ;конец строки
cmp al, ' '
je parmSeparator ;разделитель
cmp al, 9
je parmSeparator ;разделитель
stosb ;символ имени - копируем
inc cx ;считаем
jmp ParmLoop ;по всем
parmSeparator: ;разделитель
jcxz parmLoop ;разделители в начале строки пропускаем
endParm: ;конец строки
stc ;сначала пометим, что нет параметра
jcxz parmRet ;счетчик символов нет - точно нет параметра
mov al, 0 ;есть, завершаем строку нулем
stosb
clc ;и помечаем, что параметр задан
parmRet:
ret
GetParm endp
PrintNum proc ;вывод беззнакового числа из ax
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
ret
PrintNum endp
.data
;строки сообщений
sGetIn db 0dh,0ah,'Enter file name: $'
sRows db 0dh,0ah,'Rows count = $'
sAny db 0dh,0ah,'Press any key$'
sOpenErr db 0dh,0ah,'File open error!$'
sReadErr db 0dh,0ah,'File read error!$'
buf label byte ; буфер для приема строки с клавиатуры (по ф-и 0ah)
max db 128 ; максимальная длина строки
len db 0 ; реальная длина введенной строки
string db 128 dup (?) ; сама строка
buffer db 1000h dup(?) ;буфер для чтения файла
end start
----- Люби своего ближнего, как самого себя
Ответ отправил: Лысков Игорь Витальевич (Старший модератор)
Ответ отправлен: 03.06.2011, 11:51
Номер ответа: 267559 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru
Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"?
Отправить SMS#thank 267559
на номер 1151 (Россия) |
Еще номера »
Оценить выпуск »
Нам очень важно Ваше мнение об этом выпуске рассылки!
* Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи.
(полный список тарифов)
** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
*** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.