Текстовые файлы
Средства для работы с текстовыми файлами содержатся в пакетах Ada.Text_IO, Ada.Float_Text_IO, Ada.Integer_Text_IO.
Данные в текстовом файле запоминаются в виде символов. Текстовый файл — это набор символов, группируемых в строки переменной длины. Поэтому способ доступа к элементам текстового файла — только последовательный. Текстовый файл не имеет фиксированного размера. Конец файла отмечается специальным символом End_Of_File (обозначается как ). Точная форма представления символа-маркера зависит от операционной системы.
При создании текстового файла с помощью программы-редактора для разделения файла на строки нажимается клавиша Enter.
Каждый раз при нажатии на Enter в файл помещается другой специальный символ-маркер End_Of_Line (обозначается ).Обсудим содержание текстового файла, который состоит из двух строк букв, символов пробела и символов пунктуации:
Это текстовый файл!
Он содержит две строки.
Каждая строка заканчивается маркером . В последней строке за маркером следует маркер . При просмотре содержимого файла каждая строка файла представляется как отдельная строка экрана. В реальном дисковом файле символы запоминаются в последовательности байтов памяти, каждый символ — в своем байте памяти. Байт первого символа второй строки (буква О) следует за байтом первого маркера .
Текстовый файл может также содержать числовые данные или комбинацию числовых и буквенных данных.
Следующий файл включает числовые данные и символы пробела:12345 6789
777 -11
Каждое число записывается на диске как последовательность цифровых символов. Символы пробелов разделяют числа, входящие в одну строку.
В диалоговой программе Ада рассматривает данные, вводимые с клавиатуры, так, как будто они читаются из предопределенного файла Standard_Input. Нажатие клавиши Enter вводит маркер в этот файл. В диалоговом режиме для индикации окончания данных мы обычно используем сигнальную метку, а не пытаемся ввести маркер в системный файл Standard_Input. Впрочем, мы
Текстовые файлы |
547 |
можем использовать маркер . Его «клавиатурное» представление зависит от операционной системы. Наиболее часто используются комбинации Ctrl-Z или Ctrl-D. В свою очередь, отображение символов на экране эквивалентно записи символов в предопределенный файл Standard_Output. Маркер помещает в этот файл процедура New_Line. В результате курсор перемещается в начало новой строки экрана. Стандартные файлы Standard_Input и Standard_Output являются текстовыми файлами, содержащими символы. При работе со стандартными файлами процедуры Create (для Standard_Output) и Open (для Standard_Input) в программе не указываются. Эти процедуры вызываются и выполняются автоматически, по умолчанию. Не ссылаются на эти файлы (с помощью файловых объектов) и в стандартных процедурах ввода-вывода типа Get,Put, Skip_Line, New_Line. Маркеры и отличны от других символов в текстовом файле, так как не являются символами данных. Фактически в стандарте для Ады они даже не определены, так как их представление зависит от операционной системы. Однако если программа попытается прочитать , генерируется исключение End_Error. Для обработки этих маркеров в пакет Ada.Text_IO введены две функции. Эти функции позволяют определить — не является ли следующий символ маркером или . Функция End_Of_Line ( ) возвращает значение True, если следующий символ является маркером . Функция End_Of_File ( ) возвращает значение True, если следующий символ является маркером . ПРИМЕЧАНИЕ --------------------------------------------------------------------------------------------------- Для стандартных файлов ввода-вывода аргумент в этих функциях не указывается. |
Алгоритм обработки файла данных на основе этих функций имеет вид:
Если файл данных не пуст, то начальный вызов End_Of_File вернет значение False и будет выполняться внутренний цикл. Этот цикл обрабатывает каждый символ в строке, за исключением . Например, для представленного выше 2-строчного файла первое выполнение внутреннего цикла обработает первую строку: Это текстовый файл! |
548 |
Глава 18. Ввод-вывод и файлы |
Как только следующим символом станет , функция End_Of_Line вернет значение True и внутренний цикл прекратится. Маркер обрабатывается во внешнем цикле сразу после выхода из внутреннего цикла. Каждое повторение внешнего цикла начинается с вызова функции End_Of_File для проверки — не является ли следующим символом маркер . Если это правда, функция возвращает True и внешний цикл прекращается. Если это неправда, то снова выполняется внутренний цикл. Он обрабатывает следующую строку данных (до ). Для нашего примера второе выполнение внутреннего цикла обработает вторую строку символов: Он содержит две строки После обработки второго следующим символом будет , функция End_Of_File вернет True, и прекращается внешний цикл. Для обработки произвольных текстовых файлов предусмотрены такие же процедуры, что и для стандартных файлов ввода-вывода. Единственное отличие — в список аргументов добавляется имя соответствующего внутреннего файла (указывается как первый аргумент).Рассмотрим несколько примеров. Если переменная NextCh имеет тип Character, то оператор вызова Get ( Item => NextCh ); заносит следующий символ данных, набранный на клавиатуре, в переменную Next. В действительности это сокращенная форма следующего оператора: Get ( File => Ada.Text_IO.Standard_Input, Item => NextCh ); Оператор Get ( File => InData, Item => NextCh ); заносит следующий символ из файла InData в переменную NextCh. На этот «следующий» символ показывает указатель файла, который после каждого чтения автоматически передвигается. Аналогичным образом операторы Put ( Item => NextCh ); Put ( File => Ada.Text_IO.Standard_Input, Item => NextCh ); отображают значение NextCh на экране. Оператор Put ( File => OutData, Item => NextCh ); записывает значение NextCh в конец файла OutData. Оператор New_Line (OutData) записывает в файл OutData маркер . Для текстовых файлов разрешены три режима работы: In_File -- только ввод из файла -- начало - с первого элемента Out_File -- только вывод в файл -- начало - с первого элемента Append_File -- только вывод-добавление в файл -- начало - за последним элементом Если операция обработки не соответствует режиму открытого файла, то возбуждается исключение Mode_Error. Элементы текстовых файлов могут иметь следующие типы: Character, String, числовые и перечисляемые типы. |
Текстовые файлы |
549 |
Программа 18.1 Следующая программа копирует данные, набираемые на клавиатуре, в файл с именем Data.txt. Файловый объект OutData связывается с создаваемым файлом Data.txt, а затем используется для записи в этот файл. Если файл не может быть создан, генерируется исключение Name_Error.
Программа 18.2 Следующая программа выводит на экран содержимое дискового файла Data. txt (который уже существует). |
550 |
Глава 18. Ввод-вывод и файлы |
Программа 18.3 Следующая программа добавляет экземпляры целого типа Numbers в существующий дисковый файл Data.txt.
ПРИМЕЧАНИЕ --------------------------------------------------------------------------------------------------- ■ Процедура Skip_Line () применяется при чтении данных из дискового файла. Она перемещает «стрелку» указателя текстового файла в начало новой строки. ■ Процедура New_Line () применяется при записи данных в дисковый файл. Она записывает в конец файла маркер . Если между операторами вызова Put (, Ch) пропущен оператор New_Line (), то в файле будет отсутствовать разбивка на строки, то есть данные файла образуют одну длинную строку. ■ Если, например, в программе 18.1 пропустить оператор Skip_Line, то после записи в дисковый файл одной строки в него будут записываться только маркеры . |
Программа 18.4 Разработаем пакет для ввода/вывода календарных дат. Создадим его на основе стандартного пакета службы времени Ada.Calendar. Пакет Ada.Calendar содержит определение приватного типа T ime. Текущее значение переменной этого типа возвращает функция Clock. В пакете имеются функции Year, Month, Day. Они возвращают числовые значения типов Year Number, Month Number, Day_Number. |
Текстовые файлы |
551 |
Month: Months; Yean : Ada.Calendar.Year_Number; end record; procedure Get ( Item : out Date ); procedure Put ( Item : in Date ); function Today return Date; end Calendar_Dates; with Ada.Text_IO, Ada.Calendar, Ada.Integer_Text_IO; use Ada.Integer_Text_IO; package body Calendar_Dates is package Month_IO is new Ada.Text_IO.Enumeration_IO ( Months ); procedure Get ( Item : out Date ) is begin -- вводит дату в формате DD MMM YYYY Get ( Item.Day ); Month_IO.Get ( Item.Month ); Get ( Item.Year ); end Get; procedure Put ( Item : in Date ) is begin -- отображает дату в формате DD MMM YYYY Put ( Item.Day, width => 1 ); Ada.Text_IO.Put (' '); Month_IO.Put ( Item.Month, width => 1 ); Ada.Text_IO.Put (' '); Put ( Item.Year, width => 4 ); end Put; function Today return Date is -- возвращает текущую дату Now : Ada.Calendar.Time; Tmp : Date; begin Now := Ada.Calendar.Clock; -- получение кода времени Tmp.Day := Ada.Calendar.Day ( Now ); -- извлечение дня из кода времени Tmp.Month := Months'Val (Ada.Calendar.Month (Now)-1); Tmp.Year := Ada.Calendar.Year ( Now ); -- извлечение года из кода времени return Tmp; end Today; end Calendar_Dates; Клиентом этого пакета может быть следующая программа: with Ada.Text_IO, Calendar_Dates, Ada.Integer_Text_IO; use Ada.Integer_Text_IO, Ada.Text_IO, Calendar_Dates; procedure Test_Dates is D : Date; begin D := Today; Put (" Today is "); Put ( D ); -- процедура из пакета Calendar_Dates; New_Line; Put (" Please, enter a date (DD MMM YYYY)> "); Get ( D ); -- процедура из пакета Calendar_Dates; New_Line; Put (" You entered: "); Put ( D ); end Test_Dates; |
552 |
Глава 18. Ввод-вывод и файлы |