ЛАБОРАТОРНЫЙ ПРАКТИКУМ: «ПРОГРАММИРОВАНИЕ НА ФОРТРАНЕ»
СТРУКТУРА ПРАКТИКУМА
ВВЕДЕНИЕ
ВАЖНАЯ ИНФОРМАЦИЯ
1. ПРАВИЛА ЗАПИСИ ПРОГРАММЫ
1. Набор символов Фортрана
2. Форматы записи программы
3. Фиксированный формат
4. Свободный формат
2. ТРАНСЛЯЦИЯ ПРОГРАММЫ
1. Программа в одном исходном файле
2. Трансляция исходного файла
3. Трансляция нескольких исходных файлов
4. Трансляция модулей
3. КОНЦЕПЦИЯ ДАННЫХ ЯЗЫКА ФОРТРАН
1. Имена (идентификаторы)
2. Понятие типа
3. Буквальные константы
4. Разновидности типов и диапазоны значений
5. Скалярные переменные и константы
6. Массивы
7. Производные типы данных
4. ВЫРАЖЕНИЯ И ПРЕОБРАЗОВАНИЕ ТИПОВ
1. Скалярное присваивание
2. Арифметика Фортрана
3. Логические выражения
4. Работа с текстовыми строками
5. Операции с массивами
5. УПРАВЛЯЮЩИЕ ОПЕРАТОРЫ
1. Условный оператор и конструкция IF
2. Оператор варианта – конструкция CASE
3. Циклы – разновидности конструкции DO
4. Оператор GO TO
6. ВВОД/ВЫВОД ДАННЫХ
1. Простейшие операции ввода/вывода
2. Форматный ввод/вывод данных
3. Ввод/вывод массивов в неявных циклах
4. Файловый ввод/вывод
7. ПРОГРАММНЫЕ КОМПОНЕНТЫ И ЭЛЕМЕНТЫ ООП
1. Структура программных компонентов
2. Внешние подпрограммы
3. Внутренние подпрограммы
4. Модули как библиотеки производных типов
5. Встроенные функции Фортрана
ЗАДАЧИ ДЛЯ ПРОГРАММИРОВАНИЯ
6.4. Файловый ввод/вывод
В предыдущих пунктах, посвященных вводу/выводу данных, рассматривалось взаимодействие со стандартными устройствами: клавиатурой и монитором. Также упоминалось, что доступные компьютеру устройства пронумерованы, и обращение к ним осуществляется через их номера. Так, номер стандартного устройства ввода – клавиатуры, обычно «5», а номер стандартного устройства вывода – экрана монитора, обычно «6». Но поскольку эти устройства используются по умолчанию, для них предусмотрено единое обозначение – символ «звездочка».
Если быть точнее, то внешние устройства и их номера в Фортране, всегда относятся к файлам – т.е. программа считывает данные и записывает их в файлы, связанные с устройствами. Например, в UNIX, стандартное устройство «5» ассоциируется с файлом потока стандартного ввода stdin, а стандартное устройство за номером «6» – с файлом потока стандартного ввода stdout. Не зарезервированные номера устройств (а это практически все множество буквальных целых констант) по умолчанию связаны с жестким диском компьютера – т.е. эти номера можно ассоциировать с файлами жесткого диска – обычно для этого хватает первых четырех номеров от «1» до «4».
Пример 6.12. Открытие, запись, чтение и закрытие файлов.
program FINOUT1 real :: X=1., Y=2., Z=3. !Открытие пустого файла, запись данных и закрытие файла open(1, file= "info.txt") write(1,*) X, Y, Z close(1) !Открытие существующего файла, чтение данных и закрытие файла open(1, file='info.txt') read(1,*) X, Y, Z close(1) !Вывод на экран данных, считанных из файла print*, X, Y, Z end
Ассоциирование файла с номером устройства важный технологический момент, предшествующий чтению или записи данных. Сначала внешний файл связывается с номером устройства и открывается оператором OPEN, затем производится чтение или запись данных операторами READ или WRITE. После необходимых операций чтения и записи файл закрывается оператором CLOSE, с освобождением номера устройства и освобожденный номер можно использовать для дальнейших файловых операций (Пример 6.12).
В результате работы этой программы в текущей директории появится файл «info.txt» – обычный текстовый файл. Однако использованные умолчания требуют детальных разъяснений.
Оператор OPEN в развернутом виде содержит весьма значительный перечень спецификаторов. Наиболее часто применяемыми из них являются:
- Номер устройства: спецификатор UNIT
- Имя файла: спецификатор FILE;
- Статус файла: спецификатор STATUS;
- Способ доступа к данным: спецификатор ACCESS;
- Длина записи: спецификатор RECL;
- Представление данных: спецификатор FORM;
- Статус ввода/вывода: спецификатор IOSTAT.
Спецификатор UNIT является обязательным: например, UNIT=1 в рассмотренном примере. При этом достаточно указать только номер, в данном случае это «1». Можно использовать любые номера, кроме «5» и «6», зарезервированных под стандартные устройства или иных зарезервированных, если таковые имеются.
Спецификатор FILE – это текстовое выражение, переменная или константа содержащая имя файла в формате, предусмотренном операционной системой – в рассмотренном примере это файл в текущей директории: FILE = «INFO.TXT».
Спецификатор STATUS – статус файла с именем, определенным в спецификации FILE – определяется как скалярной текстовой величина с одним из пяти перечисленных значений:
- «OLD» – открывается уже существующий файл.
- «NEW» – создается новый, еще несуществующий файл.
- «REPLACE» – если файл не существует, то он будет создан, а существующий файл, будет удален и создан новый файл с тем же именем.
«SCRATCH» – создается временный файл, который удаляется после закрытия. Для SCRATCH-файла спецификатор FILE не имеет смысла и не используется.
«UNKNOWN» –для существующего файла устанавливает статус «OLD», а для несуществующего – статус «NEW». «UNKNOWN» назначается по умолчанию, если спецификатор STATUS явно не прописан в операторе OPEN (Пример 6.12).
Когда статус файла явно не задан, то при компиляции программы иногда выдается соответствующее предупреждение (warning), которое начинающие программисты часто принимают за ошибку.
Спецификатор ACCESS – способ доступа к данным определяется скалярным текстовым выражением, принимающим одно из двух значений: «SEQUENTIAL» (файл последовательного доступа) или «DIRECT» (файл прямого доступа). Файлы прямого доступа состоят из записей одинаковой длины, и к произвольной записи файла можно обратиться по ее номеру. Файлы последовательного доступа могут состоять из записей произвольной длины, а от текущей записи можно перейти только к следующей или предыдущей. Если способ доступа к данным явно не указан (Пример 6.12), то считается что это файл последовательного доступа.
Спецификатор RECL – длина одной записи файла (в байтах или машинных словах) актуальна только для файлов прямого доступа.
Спецификатор FORM – задается скалярным текстовым выражением и определяет форму представления данных: «FORMATTED», соответствующее форматному представлению данных или «UNFORMATTED» – соответствующее бесформатному представлению данных. Если форма представления не указана, то файл последовательного доступа считается форматным (Пример 6.12), а файл прямого доступа бесформатным. Форматный (по сути текстовый) файл содержит данные в удобочитаемом для человека виде. Эти данные могут считываться и записываться с использованием спецификаций формата. Бесформатный файл не предполагает визуального прочтения и хранит данные во внутреннем машинном представлении.
Спецификатор IOSTAT – характеризует состояние ввода/вывода и задается как любая целая скалярная переменная, например IOSTAT= IOS, при этом IOS = 0 означает успешную операцию ввода/вывода, а любое другое значение констатирует ошибку.
Для предъявления оператора OPEN в развернутом виде целесообразно разделить Пример 6.12 на две части (Примеры 6.13 и 6.14).
Пример 6.13. Оператор OPEN в развернутом виде.
program FINOUT2 real :: X=1., Y=2., Z=3. open(unit=1, file= "info.txt", status="new", access= "sequential",& form="formatted", iostat =IOS) if (IOS /=0) then print*, "Ошибочка вышла! " stop !Оператор останова программы end if write(1,*) X, Y, Z close(1) end
Если при запуске программы (Пример 6.13) в текущей директории присутствует файл «INFO.TXT» с явно указанным для него статусом «NEW» в операторе OPEN, то программа завершится по ошибке: «IOS > 0». Файл «INFO.TXT» является результатом работы программы и должен появиться после ее запуска.
Пример 6.14. Открытие, запись, чтение и закрытие файлов.
program FINOUT3 open(unit=4, file= "info.txt", status=″old″, access= "sequential",& form="formatted", iostat =IOS) if (IOS /=0) then print*, "Ошибочка вышла! " stop !Оператор останова программы end if read(4,*) X, Y, Z close(4) print *, X, Y, Z end
Для корректной работы программы (Пример 6.14) требуется наличие в текущей директории файла «INFO.TXT» – результата работы предыдущего примера. Если такого файла не окажется, то программа завершится с ошибкой: «IOS > 0», поскольку для файла данных «INFO.TXT» явно указан статус «OLD» в операторе OPEN.
В операторах READ и WRITE при работе с текстовыми файлами могут использоваться все дескрипторы формата ввода/вывода данных (п.6.3). Однако, помимо номера устройства и спецификации формата, операторы READ и WRITE могут содержать и другие спецификаторы – например спецификатор IOSTAT в точности такой же, как для оператора OPEN.
Наличие спецификатора IOSTAT в операторах READ и WRITE позволяет программисту самостоятельно обрабатывать ошибки чтения и записи в штатном режиме, без прерывания работы программы. Это может быть весьма актуально при обработке текстовых файлов с заранее неизвестным количеством текстовых строк, например, при копировании одного файла в другой (Примере 6.15).
Для работы этого примера в текстовом редакторе потребуется подготовить небольшой текстовый файл с именем «FILE1.TXT», в котором не менее трех строк, каждая не длиннее 80-ти символов. На выходе программа создаст копию файла «FILE1.TXT» в файле с именем «FILE2.TXT».
Пример 6.15. Копирование файлов.
program FINOUT4 character (LEN =80) STRING open(unit=1, file= "file1.txt") open(unit=2, file= "file2.txt") do read (1, ‘(A80)’, iostat = IOS) STRING write (2, ‘(A80)’) STRING if (IOS >0) exit ! Цикл завершен по достижении конца файла end do close(1); close(2) end
При открытии существующего текстового файла оператором OPEN, текущая позиция чтения находится перед первой записью файла. Чтение первой записи перемещает позицию к следующей записи и т.д. При открытии нового файла и записи последовательно добавляются в конец файла – где постоянно находится позиция для записи. В связи с этим ля файлов последовательного доступа представляет интерес позиционирование внутри файла.
При помощи оператора BACKSPACE можно из любой позиции файла перейти к предыдущей (или только что прочитанной) записи файла, а при помощи оператора REWIND – перейти к началу файла. В качестве параметра оба оператора используют номер ассоциированного с файлом устройства, например «BACKSPACE 1» или «REWIND 4». Если файл уже позиционирован в начало, то применение этих операторов не повлечет за собой ошибки или изменения в позиционировании. Проиллюстрировать возможности позиционирования можно на своеобразном «плеере» файла с элементами «перемотки» записей (Пример 6.16). Для работы программы потребуется текстовый файл с именем «FILE1.TXT», с несколькими строками, не длиннее 80-ти символов.
Пример 6.15. «Перемотка записей» текстового файла.
program FINOUT5 integer(kind=1):: ACTION, IOS=0 character (LEN =80) STRING open(unit=1, file= "file1.txt") do read (1, '(A80)' , iostat = IOS) STRING if (IOS /=0) exit ! Цикл завершен по достижении конца файла print '(A80)', STRING ! Печать строки, считанной из файла print '("1 - читать дальше, 2 - шаг назад 3 - в начало, ", i1 $)' read *, ACTION if (ACTION ==1) cycle if (ACTION ==2) then backspace 1; backspace 1 ! backspace 2 раза, иначе: !backspace + read из файла = стояние на месте endif if (ACTION ==3)rewind 1 end do print *, "Достигнут конец файла" close(1) end
В заключение, стоит отметить, что в любой позиции файла, используя оператор ENDFILE, можно внести запись «Конец файла», при этом все последующие строки файла будут утеряны. В качестве параметра оператору ENDFILE указывается номер устройства, так же как для BACKSPACE и REWIND.
Описание программирования ввода/вывода прямого доступа (ACCESS = «DIRECT») и бесформатной формой представления данных (FORM = «UNFORMATTED») выходит за рамки данного учебного пособия.