Чтение, запись, позиционирование в файле 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Чтение, запись, позиционирование в файле



Имеются два основных метода доступа к файлам: последовательный и прямой. Однако и последовательные файлы, и файлы прямого доступа хранятся на диске одинаково: как непрерывная последовательность байтов. Реально эти два типа файлов различаются по расположению в них данных и по методу доступа к этим данным.

Последовательные файлы помещают элементы данных один за другим независимо от их длины, разделяя эти элементы парой символов: возвратом каретки (ASCII 13) и переводом строки (ASCII 10). Языки высокого уровня вставляют эти символы автоматически; программы на языке ассемблера должны сами заботиться о вставке этих символов после записи каждой переменной в файл. В последовательных файлах могут храниться и числа, и строки. Числа по соглашению записываются в строковом виде. Поскольку элементы данных имеют переменную длину, то невозможно узнать, где в файле расположен определённый элемент. Для поиска нужного элемента программа должна читать файл сначала, отсчитывая нужное число пар «возврат каретки/ перевод строки». По этой причине файлы такого формата называются последовательными. Как правило, с диска в память передаётся весь такой файл.

Файлы прямого доступа заранее отводят фиксированное место под каждый элемент данных. Если какой-то элемент данных не занимает всё отведённое пространство, остаток заполняется пробелами. Поскольку каждый элемент занимает одинаковое число байт, то можно легко вычислить местоположение конкретного элемента. Как правило, связанный набор данных группируется в запись. Каждая запись содержит несколько полей, создающих набор номеров байтов, начиная с которых пишутся данные элементы. Каждая запись следует непосредственно за предшествующей безо всяких ограничителей типа «возврат каретки/ перевод строки». При этом записи можно делать в любом порядке. Файлы прямого доступа остаются на диске. В памяти присутствуют только отдельные записи, с которыми в данный момент времени идёт работа.

Система хранит файловый указатель для каждого буфера файла. Он указывает на n -ый байт файла, с которого будет начинаться следующая операция чтения или записи. Когда данные добавляются к последовательному файлу, то указатель первоначально устанавливается на конец файла. При чтении файловый указатель устанавливается на начало файла, последовательно перемещаясь от одного элемента к другому. При обращении к записи в файле прямого доступа положение записи вычисляется в виде смещения относительно начала файла, и указатель устанавливается равным этому значению. Затем нужная запись читается или пишется. Обычно за файловым указателем следит ОС. Однако программа сама может управлять им для своих специальных нужд.

Установка текущей файловой позиции. Чтение – запись в файле производятся с текущей файловой позиции, на которую указывает файловый указатель.

Установить текущую файловую позицию можно с помощью функции 42 h (помещается в регистр AH) прерывания 21 h. В регистр BX помещается дескриптор файла, полученный при его открытии. Пара регистров CX: DX содержит информацию о количестве байт, на которое нужно передвинуть указатель (т.е. смещение новой позиции в файле относительно начальной), и вычисляется по формуле: CX 65536+ DX. В регистр AL помещается начальное положение в файле, относительно которого производится операция чтения/ записи: 00 h – смещение (беззнаковое значение в CX: DX) относительно начала файла; 01 h – смещение (значение со знаком в CX: DX) относительно текущей позиции в файле; 02 h – смещение (значение со знаком в CX: DX) относительно конца файла.

Если функция выполнилась успешно, то флаг переноса CF равен 0, а пара регистров DX: AX содержит значение новой позиции в байтах относительно начала файла. В противном случае флаг переноса устанавливается в 1, а в регистр AX возвращается код ошибки: 1 – недопустимое значение в AL, 6 – недопустимый номер файла.

Методы позиционирования, заданные значением в регистре AL, по-разному трактуют величину в паре регистров CX: DX. Если AL = 00 h, то метод позиционирования понимает значение в CX: DX как абсолютное. Два других метода (AL = 01 h и AL = 02 h) рассматривают значение в CX: DX как значение со знаком. Необходимо быть внимательным при выполнении операции позиционирования, чтобы избежать последующих ошибок при операциях чтения/ записи:

– значение в CX: DX указывает на позицию перед началом файла – в этом случае последующая операция чтения/ записи будет выполнена с ошибкой;

– значение в CX: DX указывает на позицию за концом файла – в этом случае последующая операция чтения/ записи приведёт к расширению файла в соответствии со значением в CX: DX.

Например, чтобы сдвинуть указатель на конец файла, в регистр AL надо поместить значение 02 h, а содержимое регистров CX и DX обнулить. Чтобы сдвинуть файловый указатель на начало файла, надо в регистр AL поместить величину 00 h, а содержимое регистров CX и DX обнулить.

Чтение из файла и запись данных в файл последовательного доступа. 1. Функция 3 FH прерывания 21 h позволяет читать данные из файла последовательно. Предварительно файл должен быть открыт; при этом файловый указатель автоматически устанавливается на первый байт файла. Файловый указатель уникален для каждого файла: операции над другими файлами не меняют его позицию. Дескриптор открытого файла помещается в регистр BX, а требуемое для чтения число байтов в – регистр CX. Программа должна отвести место под временный буфер, в который будут читать данные из файла. Такой буфер можно создать прямо в сегменте данных программы. Тогда пара регистров DS: DX должна указывать на этот буфер.

Если операция чтения выполняется без ошибок, то флаг переноса равен 0, а в регистр AX возвращается число реально прочитанных байтов. Если AX равен 0, то достигнут конец файла. Если при чтении произошла ошибка, то в AX возвращается код ошибки: 5 – ошибка оборудования, 6 – неверный дескриптор файла.

2. Необходима внимательность при открытии последовательного файла для записи данных. Поскольку та же самая функция используется для записи в файл прямого доступа, то при закрытии файла его длина не устанавливается равной последней позиции файлового указателя.

При открытии последовательного файла для перезаписи надо использовать функцию 3 Ch прерывания 21 h, описанную ранее. Эта функция обычно создаёт новый файл, но, если он существует, то обрезается до нулевой длины, т.е. файловый указатель устанавливается равным 0. В регистр BX помещается номер файла, в регистр CX – число записываемых байтов. Пара регистров DS: DX должна указывать на первый байт буфера записываемых данных. После этого в регистр AH помещается функция 40 h и вызывается прерывание 21 h. Если ошибок при записи не произошло, то флаг переноса равен 0, а в регистр AX возвращается число реально записанных данных. В противном случае в AX возвращается код ошибки: 5 – ошибка оборудования, 6 – неверный дескриптор файла.

Для добавления записей в последовательный файл его необходимо открыть с помощью функции 3 Dh прерывания 21 h, описанную ранее. Файловый указатель должен быть установлен на конец файла, иначе существующие данные будут перезаписаны (функция 42 h прерывания 21 h, приведённая выше). Далее как в предыдущем пункте.

 Чтение из файла и запись данных в файл прямого доступа. Файл прямого доступа предполагает, что его данные организованы в виде записей фиксированной длины. Таким образом, положение каждой записи может быть вычислено. ОС автоматически выполняет эти вычисления. Однако любая программа сама может выполнять эту работу, манипулируя файловым указателем.

1. Для считывания записи из файла прямого доступа необходимо вычислить позицию в файле, считать запись и поместить её в память. Далее программа должна разделить запись на поля того же размера, которые были использованы при конструировании записи. Также нужно удалить символы пробела, добавленные при заполнении полей. Далее используется та же функция 3 Ch прерывания 21 h, как описано выше.

2. Для записи данных в файл прямого доступа программа должна вычислить позицию в файле, в которую требуется установить файловый указатель (п. 1 данного разд.). Далее используется та же функция 40 h прерывания 21 h, как описано выше.

Организация поиска файлов

Для поиска файлов в каталогах используются функции 4 Eh и 4 Fh прерывания 21 h.

1. Функция 4 Eh прерывания 21 h ищет файл с заданным именем. Пара регистров DS: DX должна указывать на путь к файлу. Данная строка может содержать до 63 символов и завершаться символом ASCII 0. В регистр CX необходимо поместить слово атрибутов файла, при этом биты 0 и 5 игнорируются.

Если файл найден, то флаг переноса CF равен 0, а область DTA заполняется информацией о нём (табл. 2.4).

DTA (Disk Transfer Areaобласть передачи дисковых данных) – область переноса данных по умолчанию размером 128 байт, которая выделяется каждой программе и начинается со смещения 80h в префиксе программного сегмента. В противном случае флаг переноса устанавливается в 1, а в регистр AX возвращается код ошибки: 2 – файл не найден, 3 – несуществующий путь, 12 h – больше файлов в каталоге нет.

Таблица 2.4

Структура блока данных в DTA

Смещение Размер в байтах Описание
00h 1 Буква логического диска, если бит 7 = 0, то диск является удалённым
01h 11 Поисковый шаблон
0Ch 1 Атрибуты поиска
0Dh 2 Порядковый номер файла в каталоге
0Fh 2 № кластера начала каталога предыдущего уровня
11h 4 Резерв
15h 1 Атрибуты найденного файла
16h 2 Время создания (модификации) файла
18h 2 Дата создания (модификации) файла
1Ah 4 Размер файла
1Eh 13 Имя файла с расширением в виде ASCII -строки, завершающеяся символом ASCII 0

После анализа данной области в программе принимается решение об окончании или продолжении поиска.

2. В имени файла можно использовать символы подстановки:? – один любой символ, * – любое количество любых символов. Тогда поиск следующего появления имени файла проводится с помощью функции 4 Fh прерывания 21 h. Она подготавливается так же, как и предыдущая функция. Указатель на область DTA меняться не должен, т.е. там должен содержаться блок, заполненный данными после вызова функции 4 Eh. Если других совпадений не найдено, то флаг переноса устанавливается в 1, а в регистр AX возвращается код ошибки: 12 h – больше файлов в каталоге нет.

3. Для выполнения работы, связанной с файлами, MS DOS предоставляет возможность установить собственную область DTA.

С помощью функции 2 Fh прерывания 21 h можно получить адрес области памяти, отведённой под DTA. Этот адрес будет сформирован в регистрах ES: BX. Выделенную область впоследствии можно сделать текущей областью DTA.

Для этого можно воспользоваться функцией 1 Ah прерывания 21 h. Пара регистров DS: DX должна указывать на область, которая будет областью DTA для последующих файловых операций.

При этом все смещения и данные, формируемые функциями поиска файлов, остаются актуальными.

Управление клавиатурой

Для управления клавиатурой можно использовать функции BIOS (Basic Input-Output System) и функции ОС (рассмотрим на примере MS DOS), поскольку язык ассемблера не имеет собственный средств для работы с клавитатурой.

Клавиатура содержит микропроцессор, который воспринимает каждое нажатие на клавишу и выдаёт скан-код в порт микросхемы связи с периферией. Скан-код – это однобайтовое число, младшие 7 бит которого представляют идентификационный номер, присвоенный каждой клавише. Старший бит кода говорит о том, была ли клавиша нажата (равен 1) или освобождена (равен 0). Когда скан-код выдаётся в порт микросхемы связи с периферией, вызывается прерывание клавиатуры (INT 9). Процессор прекращает свою работу и выполняет процедуру, анализирующую скан-код. При поступлении кода от клавиши сдвига или переключателя изменение статуса записывается в память – слово состояния клавиатуры, расположенного по адресу 0040 h:0017 h. Во всех остальных случаях скан-код трансформируется в код символа, при условии, что он подаётся при нажатии клавиши. В противном случае скан-код отбрасывается. После установки клавиш сдвига и переключателей введённый код помещается в буфер клавиатуры, который является областью памяти, способной запомнить вводимые символы пока программа слишком занята, чтобы обработать их.

Выделяют два типа кодов символов: ASCII -коды и расширенные коды.

ASCII -коды – это однобайтовые числа, включающие в себя символы пишущей машинки, ряд специальных букв и символов псевдографики, а также 32 управляющих кода (обычно используются для передачи команд периферийным устройствам). В любом случае, каждый из названных кодов имеет соответствующий символ, который может быть выведен на экран.

Расширенные коды присвоены клавишам или комбинациям клавиш, которые не имеют представляющего их символа ASCII. Расширенные коды имеют длину 2 байта, причём первый байт всегда равен ASCII 0. Второй байт – номер расширенного кода (табл. 2.5).

Таблица 2.5

Сводная таблица расширенных кодов

Значение 2-го байта Соответствующие клавиши
15 Shift+Tab
16 – 25 Alt+Q – Alt+P (верхний ряд букв)
30 – 38 Alt+A – Alt+L (средний ряд букв)
44 – 50 Alt+Z – Alt+M (нижний ряд букв)
59 – 68 Функциональные клавиши F1 – F10
71 Home
72 Cursor-Up (стрелка вверх)
73 PageUp
75 Cursor-Left (стрелка влево)
77 Cursor-Right (стрелка вправо)
79 End
80 Cursor-Down (стрелка вниз)
81 PageDown
82 Ins
83 Del
84 – 93 F1 - F10+Shift
94 – 103 F1 – F10+Ctrl
104 – 113 F1 – F10+Alt
114 Ctrl+PrtSc
115 Ctrl+Cursor-Left
116 Ctrl+Cursor-Right
117 Ctrl+End
118 Ctrl+PageDown
119 Ctrl+Home
120 – 131 Alt+1 – Alt+= (верхний ряд)
132 Ctrl+PageUp

 

Например, код 0:30 представляет Alt + A. Начальный ноль позволяет программе определить, принадлежит ли данный код набору ASCII или расширенному набору.

Существует несколько комбинаций клавиш для выполнения специальных функций, они не генерируют скан-коды. Например, «Ctrl + Break», «Ctrl + Alt + Del». Их нажатие приводит к заранее предопределённым результатам.

Очистка буфера клавиатуры. Программа должна очистить буфер клавиатуры перед тем, как выдать запрос на ввод. Таким образом, исключаются посторонние нажатия клавиш, которые могут к тому времени накопиться в буфере. Буфер может накапливать до 15 нажатий на клавишу, независимо от того, являются ли они однобайтовыми кодами ASCII или двухбайтовыми расширенными кодами. Следовательно, буфер должен отвести 2 байта для каждого нажатия на клавишу. Для ASCII -кодов первый байт содержит сам ASCII -код символа, а второй – скан-код клавиши. Для расширенных кодов первый байт содержит ASCII 0, а второй – номер расширенного кода, который обычно совпадает со скан-кодом клавиши, но не всегда.

Сам буфер клавиатуры организован по принципу кольца, имеет размер 16 байтов и занимает в памяти диапазон адресов с 0040 h:001 Eh до 0040 h:003 Dh. В ячейке 0040 h:001 Ah хранится адрес начала (головы) буфера, в ячейке 0040 h:001 Ch – адрес конца (хвоста). Если содержимое этих ячеек равно, то буфер пуст. Когда буфер заполнен, новые символы игнорируются. Чтобы разрешить ввод 15 символов, требуется 16-я пустая позиция, 2 байта которой содержат код возврата каретки (ASCII 13) и скан-код клавиши «ENTER», равный 28.

Функция 0 Ch прерывания 21 h выполняет любую из функций ввода с клавиатуры (будут рассмотрены ниже), но предварительно чистит буфер клавиатуры. Надо просто в регистр AH поместить функцию 0 Ch, в регистр AL – номер функции для ввода символа с клавиатуры и вызвать прерывание 21 h.

Проверка наличия символа в буфере клавиатуры. Можно проверить, был ли ввод с клавиатуры, не удаляя символ из буфера клавиатуры, используя возможности BIOS или DOS.

1. Использование ОС MS DOS. Функция 0 Bh (помещается в регистр AH) прерывания 21 h возвращает в регистр AL значение 0 FFh, когда буфер клавиатуры содержит один или более символов, и 0 – в противном случае (буфер пуст).

2. Использование BIOS. Функция 1 h прерывания 16 h позволяет не только проверить наличие символа в буфере, но и показывает, какой именно символ содержится в буфере (для 84-клавишной клавиатуры). Флаг нуля ZF сбрасывается в 0, если буфер пуст, и устанавливается в 1 в противном случае. В последнем варианте копия символа, находящегося в голове буфера, помещается в регистр AX, но сам символ из буфера не удаляется. В AL возвращается код символа для однобайтовых символов ASCII, иначе, AL равен 0 для расширенных кодов, и в регистре AH помещается номер расширенного кода.

Если были нажаты дополнительные клавиши на расширенных версиях клавиатур, то при проверке символов этой функцией они удаляются из буфера. Поэтому при работе с расширенными клавиатурами следует использовать функции 11 h (для 102-клавишной) и 21 h (для 122-клавишной) прерывания 16 h соответственно.

Ввод символа с клавиатуры с ожиданием и эхом, и запись его в буфер клавиатуры. При вводе данных и текста эхо вводимых символов обычно выдаётся на экран. При этом символы возврата каретки и забоя переводятся в соответствующие перемещения курсора на экране. Выдача эха осуществляется в той позиции, где предварительно был установлен курсор. Текст автоматически переносится на другую строку при достижении конца текущей строки.

1. Использование ОС MS DOS. Функция 1 h прерывания 21 h ожидает ввода символа, если буфер клавиатуры пуст, а затем выводит его в текущую позицию курсора. Введённый символ возвращается в регистре AL. Если был введён расширенный код, то AL будет содержать 0. Для получения в AL второго байта расширенного кода надо повторить вызов прерывания 21 h.

Эта функция игнорирует нажатие клавиши «ECS», но обрабатывает «Ctrl + Break» («Ctrl + C»), выполняя при этом специальную процедуру обработки.

Для ввода нескольких символов данную функцию необходимо использовать в цикле.

2. Использование BIOS. Функция 0 h прерывания 16 h позволяет ввести символ с клавиатуры, если буфер пуст (для 84-клавишной клавиатуры). В остальном её действие аналогично действию описанной в предыдущем пункте функции 1 h прерывания 21 h. Для расширенных клавиатур используются функции 10 h (для 102-клавишной) и 20 h (для 122-клавишной) прерывания 16 h соответственно.

Ввод символа с клавиатуры без эха и без ожидания и запись его в буфер клавиатуры. Некоторые программы, работающие в режиме реального времени, не могут останавливаться и ждать нажатия клавиши.

Использование ОС MS DOS. Функция 6 h прерывания 21 h позволяет ввести один символ с клавиатуры, но, в отличие от предыдущей функции, она не ожидает ввода при отсутствии символа в буфере.

В регистр AH помещается функция 6 h, в регистр DL – значение 0 FFh, и вызывается прерывание 21 h. Флаг нуля ZF устанавливается в 1, если буфер клавиатуры пуст. Если символ принят, то он помещается в регистр AL. В случае расширенного кода действия аналогичны, как для функции 1 h, рассмотренной выше.

Данная функция не обрабатывает «Ctrl+Break» («Ctrl+C»).

Ввод символа с клавиатуры без эха с ожиданием, и запись его в буфер клавиатуры. Обычно вводимые символы отображаются на экране, но в некоторых случаях это нежелательно (например, для расширенных кодов).

Использование ОС MS DOS. Функция 7 h прерывания 21 h аналогична функции 1 h прерывания 21 h за исключением того, что не выводит его на экран в виде эха и не воспринимает сочетание клавиш «Ctrl + Break» («Ctrl + C») как прерывание программы.

Функция 8 h прерывания 21 h аналогична функции 1 h прерывания 21 h, за исключением того, что не выводит его на экран в виде эха, но воспринимает сочетание клавиш «Ctrl + Break» («Ctrl + C») как прерывание программы.

Ввод строки символов с клавиатуры. Большинство языков программирования предоставляют возможности для ввода строки символов. Они используют возможности ввода символов с эхопечатью, помещая автоматически введённые символы в буфер оперативной памяти. Конечно же, должна быть выделена память, достаточная для приёма символов строки, и должна записываться длина строки при вводе. Если этого не сделать, то произойдёт отказ системы типа «переполнение буфера».

Функция 0AH прерывания 21H позволяет вводить строку длиной до 254 символов, выдавая эхо на терминал. Эта функция продолжает ввод символов до тех пор, пока не нажата клавиша "возврат каретки" (" E NTER "). Пара DS:DX указывает на строку, куда помещаются вводимые символы. При вводе первый байт этой позиции должен содержать число байтов, отводимые для этой строки.  Если первый байт равен 0, то вызов функции игнорируется и программа продолжает выполнение без ожидания ввода строки. После того, как строка введена, второй байт даёт число реально введённых символов. Сама строка начинается с третьего байта.

Надо отвести достаточно памяти для строки нужной длины, плюс 2 байта для дескриптора строки, плюс 1 добавочный байт для символа "Возврат каретки". Код возврата каретки – ASCII 13 – вводится как последний символ строки, но не учитывается в результате, который функция помещает во второй байт дескриптора.

Таким образом, для получения 50- символьной строки надо отвести минимум 53 байта памяти, и поместить в первый байт памяти строки число ASCII 51. После ввода 50 символов второй байт дескриптора будет содержать ASCII 50, а 53-й байт отведённой памяти будет содержать ASCII 13. Функция обрабатывает нажатие комбинации клавиш «Ctrl + Break» («Ctrl + C»), останавливая ввод символов и продолжая выполнение программы.



Поделиться:


Последнее изменение этой страницы: 2020-12-09; просмотров: 206; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.133.12.172 (0.046 с.)