Жанр: Учеба
Справочник программиста на IBM PC
...писью понимается
порция данных, которая считывается из файла.
Высокий уровень.
Чтение последовательных файлов в Бейсике проще, чем их запись,
поскольку имеется только две возможности, как обращаться с ними,
в зависимости от того, какие символы в файле используются в качестве
ограничителей элементов данных. Оператор INPUT# распознает
запятые и кавычки, как разделители данных, так же как и пары
возврат каретки/перевод строки. Оператор LINE INPUT# распознает
только комбинации CR/LF, поэтому он может использоваться для
чтения целых строк текста, содержащих другие ограничители. Эта
возможность удобна при обработке текстов.
Для чтения трех элементов оператором INPUT#, сначала откройте
файл, как обсуждалось в [5.3.3] (например, OPEN "A:NEWSEQ" FOR
INPUT AS #1). Если файл был открыт под номером 1, то оператор
INPUT #1, X$, Y$, Z$ присвоит значение первых трех элементов
данных трем строковым переменным. При вводе числовых переменных,
например, INPUT #1, X, Y, Z необходимо, чтобы соответствующие
данные в файле были числовыми. Число с двойной точностью должно
считываться в переменную двойной точности, с тем чтобы она могла
хранить восемь байтов такого числа. Другой способ прочитать три
элемента данных состоит в размещении их в массиве:
100 DIM ITEM$(40) 'создаем массив строк из 40 элементов
110 FOR N = 0 TO 39 'для каждого элемента
120 INPUT #1, ITEM$(N) 'считываем его и помещаем в массив
130 NEXT '
Чтобы прочитать n-ный элемент последовательного файла программа
должна прочитать все предшествующие ему элементы. Надо просто
создать цикл, в котором будут считываться элементы данных, но не
сохранять эти данные по мере их появления.
Оператор LINE INPUT# действует в основном аналогично оператору
INPUT#, за исключением того, что он может принимать только одну
переменную и это всегда строковая переменная. Переменная может
быть длиной до 254 символов и это максимально допустимый размер
строковых переменных в Бейсике. Пара возврат каретки/перевод
строки, содержащаяся в файле, включается в строку, возвращаемую
оператором LINE INPUT#. Это свойство позволяет обнаруживать конец
параграфа в текстовом файле.
Функция EOF (конец файла) может быть использована для определения
того, все ли элементы файла были прочитаны. Эта функция
возвращает -1, если файл исчерпан и 0 - в противном случае. Функции
требуется номер файла, под которым он был открыт; например,
если был был открыт как #2, то X = EOF(2). В следующем примере
весь текстовый файл считывается в массив:
100 OPEN "TEXT.AAA" FOR INPUT AS #2 'открываем файл
110 DIM TEXT$(500) 'не более 500 строк
120 LINECOUNT = 0 'счетчик строк
130 LINE INPUT #2, TEXT$(LINECOUNT) 'получаем строку
140 IF EOF(2) THEN 170 'проверка на конец файла
150 LINECOUNT = LINECOUNT + 1 'увеличиваем счетчик
160 GOTO 130 'на следующую строку
170 ... 'файл прочитан
Оператор INPUT$ читает из последовательного файла указанное
число символов. На самой программе лежит забота о выделении отдельных
элементов данных. Формат этого оператора для чтения 30
символов из файла #1 такой: S$ = INPUT$(30,#1). Хотя Вы можете
указывать число байт для чтения, необходимо чтобы это число не
превосходило 254, поскольку это максимальный размер строковой
переменной, в которую помещаются данные. INPUT$ полезен при передаче
массы данных в непрерывную область памяти. Например, в следующем
примере делается дамп первых 200 байтов последовательного
файла в буфер монохромного дисплея, с тем чтобы они были выведены
на экран, включая управляющие коды:
100 OPEN "A:NEWFILE" FOR INPUT AS #1 'открываем файл
110 CLS: DEF SEG = &HB000 'указываем на буфер
120 FOR N = 0 TO 9 'получаем 10 групп
130 S$ = INPUT$(20,#1) 'по 20 байтов
140 FOR M = 1 TO 20 'берем каждый байт
150 POKE N*160 + M*2, ASC(MID$(S$,M,1) 'и помещаем его в буфер
160 NEXT M 'переход к следующему байту
170 NEXT N 'переход к следующей группе
Средний уровень.
Как и для всех файловых операций MS DOS может читать последовательные
файлы как методом управляющего блока файла, так и методом
дескриптора файлов. Только первый из них имеет функцию специально
предназначенную для чтения последовательных файлов. Метод
дескриптора файлов использует более общую функцию, манипулируя ей
особым образом, требуемым для последовательных файлов.
Метод FCB:
Функция 14H прерывания 21H читает последовательные файлы. Надо
создать управляющий блок файла и область обмена с диском, как
объяснено в [5.3.5]. Файл должен быть открыт функцией 0FH прерывания
21H [5.3.3]. DS:DX должны указывать на первый байт FCB,
после чего функция 14H будет читать по одной записи из файла при
каждом вызове. Вы можете установить размер записи по смещению 14
в FCB. Это надо делать после того, как файл открыт, так как при
открытии файла DOS вставляет в это поле значение по умолчанию,
равное 128.
Каждый раз при вызове функции данные загружаются в память,
начиная с первого байта DTA. Если DTA используется как небольшой
временный буфер, то перед чтением следующей записи содержимое DTA
должно быть перенесено в область данных файла, отведенную в памяти.
Можно наоборот установить указатель DTA на стартовый адрес
памяти, начиная с которого будет размещаться файл, а после чтения
каждой записи указатель увеличивать на размер записи, с тем чтобы
он указывал на место, где должна быть следующая запись.
Установкой полей текущей записи (DB, смещение 1FH) и блока
текущей записи (DW, смещение 0CH) отличными от нуля, последовательный
может читаться, начиная с любого требуемого места (установка
должна быть сделана после открытия FCB). После каждого
чтения поле текущей записи автоматически увеличивается на 1, а
после чтения 128 записей увеличивается поле текущего блока. При
возврате AL равен 0, если вся запись успешно прочитана. При обнаружении
конца файла AL будет содержать 1, если функция 14H вообще
не возвратила данных и 3 - если запись прочитана частично.
В приведенном примере из файла считываются две записи и последовательно
помещаются в нужную область памяти. Размер записи
установлен равным 256 байтам. Записи считываются в цикле и после
того, как первая запись считана, указатель на DTA изменяется
таким образом, чтобы он указывал на следующий пустой байт в области
данных.
;---помещаем FCB в сегмент данных
FCB DB 0,'OLDDATA DAT', 25 DUP(0)
DATA_AREA DB 512 DUP (?) ;используем как DTA
;---устанавливаем DTA на начало области данных
LEA DX,DATA_AREA ;DS:DX указывают на DTA
MOV DI,DX ;сохраняем копию
MOV AH,1AH ;функция установки DTA
INT 21H ;устанавливаем DTA
;---открываем файл
LEA DX,FCB ;DS:DX указывают на FCB
MOV AH,0FH ;функция открытия файла
INT 21H ;открываем файл
CMP AL,0 ;проверка на ошибку
JNE OPEN_ERROR ;
;---устанавливаем размер записи 256 байт
LEA BX,FCB ;DS:DX указывают на FCB
MOV AX,256 ;размер записи
MOV DS:[BX]+14,AX ;посылаем в поле размера записи
;---чтение данных
MOV CX,2 ;число читаемых записей
NEXT_REC: MOV AH,14H ;функция чтения файла
LEA DX,FCB ;DS:DX указывают на FCB
INT 21H ;читаем одну запись
CMP AL,0 ;все в порядке?
JE CONTINUE ;
CMP AL,2 ;проверка на ошибку
JE READ_ERROR ;
CONTINUE: ADD DI,256 ;увеличиваем указатель
MOV DX,DI ;DX указывает на новую DTA
MOV AH,1AH ;функция установки DTA
INT 21H ;устанавливаем DTA
LOOP NEXT_REC ;идем на чтение следующей записи
;---позднее, закрываем файл
LEA DX,FCB ;DS:DX указывают на FCB
MOV AH,10H ;функция закрытия файла
INT 21H ;закрываем файл
CMP AL,0FFH ;проверка на ошибку
JE CLOSE_ERROR ;
Метод дескриптора файлов:
Функция 3FH прерывания 21H может читать данные из файла последовательно.
Эта функция используется для любого чтения из файла с
помощью метода дескриптора файлов, включая файлы прямого доступа.
Файл должен быть открыт функцией 3DH прерывания 21H с кодом 0 в
AL, если он открывается только для чтения, и с кодом 2 - если он
открывается для чтения и записи. При открытии файловый указатель
автоматически устанавливается на первый байт файла. Функция чтения
из файла указывает сколько байтов должно быть считано и после
того как это сделано файловый указатель указывает на байт, следующий
за последним считанным байтом, подготавливая следующее
обращение к функции. Отметим, что файловый указатель уникален для
каждого файла - операции над другими файлами не меняют его позицию.
Программа может создать небольшой временный буфер, размером,
скажем, 512 байт, и постоянно вызывать функцию чтения, не заботясь
о позиции файлового указателя. Другой метод состоит в считывании
всего файла прямо в то место памяти, где он должен быть
расположен. В этом случае надо просто потребовать, чтобы функция
прочитала больше байтов, чем реально содержится в файле, так как
чтение прекращается при достижении последнего байта файла. Однако
Вам необходимо знать точную длину файла, чтобы знать где кончаются
данные в буфере, в который Вы считали файл.
Размер файла можно определить, сдвинув файловый указатель на
конец файла. Это надо сделать сразу же после открытия файла.
Поместите в AL код 2 и вызовите функцию 42H, для того, чтобы
сдвинуть указатель на конец файла. CX и DX должны содержать 0,
так как в противном случае указатель будет сдвинут с конца файла
на величину, которая содержится в этих регистрах. При возврате
DX:AX будут содержать новую позицию указателя, как смещение относительно
начала файла, т.е., в данном случае, длину файла. Не
забудьте снова вернуть файловый указатель на начало файла, перед
тем как читать его; это делается точно таким же образом, за исключением
того, что в AL надо поместить 0. Если при выполнении
функции 42H возникает ошибка, то устанавливается флаг переноса, а
в AX возвращается 1, если неверен номер функции, и 6 - если указан
неверный номер файла.
Теперь программа готова для чтения файла. Надо поместить номер
файла в BX, а требуемое число байтов в CX и выполнить прерывание.
При возврате AX будет содержать число реально прочитанных байтов.
Если AX равен нулю, то достигнут конец файла. При других ошибках
устанавливается флаг переноса, а AX содержит 5 - при ошибке оборудования
и 6 - если указан неверный номер файла. В следующем
примере в буфер памяти считывается весь небольшой файл. Для удобства
буфер располагается в сегменте данных, что существенно
увеличивает размер программы на диске. В своих программах лучше
создавать буфер, используя технику распределения памяти, описанную
в [1.3.1].
;---в сегменте данных
PATH DB 'A:FILENAME.EXT'0 ;строка пути к файлу
DATA_BUFFER DB 1000 DUP (?) ;буфер данных
HANDLE DW ? ;номер файла
FILESIZE DW ? ;размер файла
;---открываем файл
LEA DX,PATH ;DS:DX указывают на путь
MOV AL,0 ;код открытия для чтения
MOV AH,3DH ;функция открытия файла
INT 21H ;открываем файл
JC OPEN_ERROR ;проверка на ошибку
MOV HANDLE,AX ;запоминаем номер файла
;---устанавливаем файловый указатель на конец файла
MOV AH,42H ;функция установки указателя
MOV AL,2 ;код для конца файла
MOV BX,HANDLE ;номер файла
MOV CX,0 ;смещение равно нулю
MOV DX,0 ;
INT 21H ;устанавливаем указатель
JC POINTER_ERROR1 ;обработка ошибки
MOV FILESIZE,AX ;запоминаем размер (меньше 64K)
;---возвращаем указатель на начало
MOV AH,42H ;номер функции
MOV AL,0 ;код для начала файла
MOV CX,0 ;смещение равно нулю
MOV DX,0 ;
INT 21H ;устанавливаем указатель
JC POINTER_ERROR2 ;обработка ошибки
;---читаем весь файл
MOV AH,3FH ;номер функции чтения файла
MOV BX,HANDLE ;номер файла
MOV CX,FILESIZE ;число считываемых байтов
LEA DX,DATA_BUFFER ;DS:DX указывают на буфер
INT 21H ;читаем файл
JC READ_ERROR ;обработка ошибки
;---позднее, закрываем файл
MOV BX,HANDLE ;номер файла
MOV AH,3EH ;функция закрытия файла
INT 21H ;закрываем файл
JC CLOSE_ERROR ;обработка ошибки
5.4.5 Запись в файлы прямого доступа.
Физически файлы прямого доступа ничем не отличаются от последовательных
файлов, они отличаются только режимом доступа. Файл
прямого доступа предполагает, что его данные организованы в виде
записей фиксированной длины, таким образом положение каждой записи
может быть вычислено (в последовательных файлах n-ный элемент
ищется путем подсчета разделителей между элементами, начиная с
начала файла). Операционная система автоматически выполняет эти
вычтсления. Однако любая программа может выполнять эту работу
сама, устанавливая файловый указатель на нужную позицию и считывая
последовательно такое число байтов, которое образует запись.
Высокий уровень.
В [5.3.3] объяснен формат открытия файдов прямого доступа в
Бейсике. В отличии от последовательного файла, файл прямого доступа
может читаться и записываться в одно и то же время, без
закрытия и повторного его открытия. Оператор OPEN завершается
числом, дающим размер записи файла. Например, OPEN "R", 1, "NEWDATA",
20 устанавливает для файла NEWDATA размер записи в 20 байт
(при этом файл открывается как файл #1).
После того как файл открыт, его записи могут быть разбиты на
составляющие переменные с помощью оператора FIELD. Оператор FIELD
указывает сколько байтов записи отводится под каждую переменную.
Например, запись длиной 20 байт может быть разбита оператором
FIELD 1, 14 AS LASTNAME$, 2 AS DEPOSIT$, 4 AS ACCTNUM$. В этом
операторе первая цифра 1 указывает, что данный оператор FIELD
описывает разбиение записи для файла, открытого под номером #1.
Данные располагаются в записи точно в том порядке, в каком они
описаны в операторе FIELD. Опреаторы RSET и LSET сдвигают данные
в полях, выравнивая их по правому (RSET) или левому (LSET) краю и
заполняя остающиеся пустые места пробелами. Например, для того,
чтобы вставить фамилию "SMITH" в 14-байтное поле с именем LASTNAME$,
надо записать RSET LASTNAME$ = "SMITH", или если переменной
N$ было присвоено значение "SMITH", то RSET LASTNAME$ = N$. Вместо
RSET может быть использовано LSET. Когда впоследствии данные
считываются из поля в переменную, то переменной присваиваются все
14 байтов. При использовании RSET программа удалит все лишние
пробелы в начале строковой переменной, однако если будет использоваться
LSET, то пробелы будут удаляться справа.
Отметим, что все имена переменных в операторе FIELD относятся
к строковым переменным. В файлах прямого доступа Бейсик рассматривает
все переменные - включая числовые - как строковые. Числовая
переменная должна быть преобразована в специальный вид, прежде
чем ее значение может быть присвоено полю, а когда она затем
считывается из поля то необходимо обратное преобразование. Слово
преобразование стоило бы заключить в кавычки, поскольку Бейсик на
самом деле не меняет способ представления числа в памяти; он
просто обрабатывает число особым образом. Числовые поля требуют
двух байтов для целых чисел, четырех байтов - для чисел с обычной
точностью и восьми байтов - для чисел с двойной точностью. В
точности такое же число байт требуется для представления этих
чисел в памяти. Для преобразования их в строковую форму надо
использовать функции MKI$, MKS$ и MKD$, которые осуществляют
преобразование число-строка для целых, вещественных и чисел с
двойной точностью, соответственно. Обычно эти функции комбинируются
с операторами RSET или LSET, например, RSET = ACCTNUM$ =
MKI$(X), где X - целая переменная, если полю ACCTNUM$ было отведено
два байта в операторе FIELD.
После того как поля заполнены операторами RSET и LSET, запись
записывается на диск с помощью оператора PUT#. PUT #1, 245 помещает
данные в запись номер 245, файла открытого под номером #1.
Номер записи может быть опущен, в этом случае данные записываются
в запись с номером на единицу больше, чем номер последней записанной
записи (начиная с записи 1). Записывается вся запись целиком,
даже если не все поля были заполнены данными. Отметим, что
поля буфера не очищаются при выполении операции PUT, поэтому
элементы данных, такие как текущая дата, могут помещаться в буфер
только один раз, а затем они будут записаны во все записи, которые
будут записываться в течение данной сессии. Функция LOC возвращает
номер последней записанной в файл записи. Если файл был
открыт под номером #3, то напишите X = LOC(3).
Функция LOF (длина файла) возвращает длину файла в байтах. Для
определения числа записей, содержащихся в файле, надо разделить
это значение на длину записи. Добавление 1 к этому значению дает
номер записи, который надо использовать, чтобы добавить к файлу
новые записи. Если файл был открыт под номером #2, а длина его
записей равна 32 байтам, то требуемое значение вычисляется как
RECORDNUM = LOF(2)/32 + 1.
В следующем примере файл прямого доступа открывается с длиной
записи 24 байта, причем запись разбита на три переменные. Пользователь
программы запрашивается о содержимом всех трех полей, а
когда все они введены, то запись добавляется к файлу. В строке
120 вычисляется начальный номер записи. Отметим, что данные могут
не записываться физически на диск каждый раз при выполнении оператора
PUT. В выходном буфере могут накапливаться несколько записей,
прежде чем это будет сделано.
100 OPEN "R", 1, "A:NEWDATA.DAT", 24 'открываем файл
110 FIELD 1, 18 AS LASTNAME$, 2 AS AGE$, 4 AS WEIGHT
120 R = LOF(1)/24 + 1 'номер последней записи + 1
130 CLS 'чистим экран
140 INPUT "Enter name:",N$ 'получаем имя (строка)
150 INPUT "Enter age:",A% 'получаем возраст (целое)
160 INPUT "Enter weight:",W! 'получаем вес (вещественное)
170 RSET LASTNAME$ = N$ 'помещаем в поле имя
180 RSET AGE$ = MKI$(A%) 'помещаем в поле возраст
190 RSET WEIGHT$ = MKS$(W!) 'помещаем в поле вес
200 PUT #1, R 'записываем запись
210 R = R + 1 'увеличиваем счетчик
220 PRINT: PRINT "Do another (y/n)?" 'запрос пользователя
230 C$ = INKEY$: IF C$ = "" THEN 220 'ожидаем ответа
240 IF C$ = "y" THEN CLS: GOTO 130 'если да, то на начало
250 CLOSE 'иначе закрываем файл
Средний уровень.
Как и все другие операции с файлами в MS DOS имеется два метода
записи в файл прямого доступа, один с использованием управляющего
блока файла, а другой с помощью дескриптора файла. В обоих
случаях Вы должны создать буфер обмена данными, размер которого
должен быть не меньше, чем размер записи.
Метод управляющего блока файла:
Откройте управляющий блок файла с помощью функции 0FH и пусть
DS:DX указывают на него. После того как файл открыт поместите
номер записи для прямого доступа в поле записи прямого доступа
FCB. Затем вызовите функцию 22H прерывания 21H, которая пердаст
данные из DTA в файловый буфер, созданный при создании FCB. Данные
могут не быть немедленно записаны на диск, если размер записи
меньше чем размер буфера. Реальная запись на диск будет происходить
тогда, когда очередной вызов функции 22H заполнит буфер.
При возврате из функции 22H AL будет содержать 00, если обмен
прошел успешно. В противном случае в нем будет 1, если не хватает
пространства на диске и 2 - если область переноса мала для того,
чтобы записать одну запись (т.е. если размер буфера, установленный
системой меньше, чем тот, который указан в FCB).
;---в сегменте данных
FCB DB 1, 'NEWDATA ', 25 DUP (0)
DTA DB 256 DUP (?)
;---открываем файл и устанавливаем поля FCB
MOV AH,0FH ;номер функции
LEA DX,FCB ;DS:DX указывают на FCB
MOV BX,DX ;копируем смещение для FCB
INT 21H ;открываем файл
MOV AX,256 ;размер записи
MOV [BX]+14,AX ;помещаем в поле размера записи
MOV AX,233 ;номер записи
MOV [BX]+33,AX ;помещаем в поле номера записи
MOV AX,0 ;обнуляем старший байт этого слова
MOV [BX]+35,AX ;
;---перенос данных из DTA в файл
MOV AH,22H ;номер функции записи с прямым доступом
LEA DX,FCB ;DS:DX указывают на FCB
INT 21H ;записываем данные
CMP AL,0 ;проверка на ошибку
JNE WRITE_ERROR ;
;---позднее, закрываем файл
LEA DX,FCB ;DS:DX указывают на FCB
MOV AH,10H ;функция закрытия файла
INT 21H ;закрываем файл
CMP AL,0FFH ;проверка на ошибку
JE CLOSE_ERROR ;
Часто программа работает сразу с набором записей прямого доступа,
передавая их в память и из памяти как единое целое. MS DOS
предоставляет специальную функцию для этого при использовании
метода FCB, называемую запись блока с прямым доступом. Это функция
28H прерывания 21H. При входе DS:DX должны указывать на открытый
FCB, в котором поле записи прямого доступа должно быть
равно номеру первой из записываемых записей набора. Эта функция
совершенно аналогична вышеприведенному примеру. Единственное
отличие (кроме номера функции) состоит в том, что в CX должно
быть указано число записей в блоке (не путайте эти "блоки" с
блоками по 128 записей, с помощью которых система находит требуемую
запись - программа может читать любое число записей, начиная
с любого места).
В CX возвращается число реально прочитанных записей. AL будет
содержать 0, если все записи успешно записаны, 1 - если не хватает
пространства на диске, при этом не будет записана ни одна
запись. В отличии от функции 22H эта функция автоматически увеличивает
поля текущей записи, текущего блока и записи прямого доступа
в FCB, так что они будут указывать на запись, следующую за
последней прочитанной. Отметим, что если при выполнении этой
функции установить CX = 0, то размер файла будет установлен в
соответствии с числом записей, равным полю записи прямого доступа,
и таким образом можно резервировать для файла дисковое пространство.
Метод дескриптора файлов:
При использовании для доступа метода дескриптора файлов система
не различает последовательные файлы и файлы прямого доступа.
Ваша программа должна вычислить позицию в файле, с которой начинается
требуемая запись, и установить на нее файловый указатель.
Файловый указатель позиционируется с помощью функции 42H прерывания
21H. Поместите номер файла в BX, а смещение в файле в CX:DX
(CX будет содержать старший байт значения). Затем поместите в AL
кодовый номер от 0 до 2. При AL = 0, указатель будет установлен
со смещением CX:DX байтов относительно начала файла; при AL = 1,
указатель будет установлен со смещением CX:DX относительно текущей
позиции, а при AL = 2, указатель будет установлен со смещением
CX:DX относительно конца файла (т.е. таким образом файл
будет расширен). Отрицательные числа недопустимы в качестве смещений.
При возврате DX:AX будут содержать новое положение указателя
(старший байт в DX). Если устанавливается флаг переноса, то
произошла ошибка. В этом случае AX будет содержать 1, если указан
неверный код в AL и 6 - если указан неверный номер файла.
После позиционирования файлового указателя запись прямого
доступа записывается с помощью той же функции 40H прерывания 21H,
которая использовалась для записи в последовательный файл. При
входе BX содержит номер файла, а CX - число байтов, которое надо
записать. При возврате AX будет содержать число реально записанных
байтов. Если оно отличается от числа помещенного в CX, то
вероятно диск полон (см. [5.1.4]). Как обычно, при возникновении
ошибки устанавливается флаг переноса. В этом случае AX будет
содержать 5 при ошибке накопителя и 6 - если указан неверный
номер файла.
Файловый указатель играет ту же роль для образа файла на диске,
что DTA для образа файла в памяти. Он может сдвигаться как
угодно для доступа к различным частям файла. Будьте внимательны,
манипулируя файловым указателем при работе с фалом прямого доступа,
содержимое любого поля любой записи может быть сразу прочитано
с диска и помещено в требуемое место в памяти.
;---в сегменте данных
HANDLE DW ? ;номер файла
FILEPATH DB 'A:NEWDATA',0 ;строка пути к файлу
REC_BUFFER DB 30 DUP (?) ;буфер выводимых записей
;---открываем файл
MOV AH,3DH ;номер функции
MOV AL,1 ;код открытия для записи
LEA DX,FILEPATH ;DS:DX указывают на путь
INT 21H ;открываем файл
JC OPEN_ERROR ;проверка на ошибку
MOV HANDLE,AX ;сохраняем номер файла
;---вычисляем позицию записи и устанавливаем файловый указатель
MOV AX,30 ;размер записи 30 байтов
MOV CX,54 ;номер записи #54 (55-я запись)
MUL CX ;теперь смещение для нее в DX:AX
MOV CX,DX ;помещаем старшее слово в DX
MOV DX,AX ;помещаем младшее слово в CX
MOV AL,0
...Поділитися у соцмережах