Дата публикации: Dec 14, 2012 10:6:30 PM
Форматный ввод/вывод - это преобразование данных из внутреннего представления в текстовое и обратно. В частности, это может быть собственно обмен между программой и внешним носителем информации, обычно файлом. Но не обязательно. В Фортране есть концепция внутреннего файла, который есть ни что иное, как символьная переменная, скалярная или массивная (ранга 1). Если скалярная, то в "файле" одна запись, если массивная - то несколько. Обычные операторы чтения и записи позволяют конвертировать числа в строки и обратно, поэтому специальных функций для этой цели нет. Огромное количество спецификаторов операторов чтения и записи (см. ниже) и дескрипторов формата дают возможность регламентировать этот процесс. Так, можно управлять режимом десятичной точки (. или ,), наличием разделителя разрядов, режимом округления и т.п., кроме того, спецификаторы позволяют обрабатывать ошибки (что необходимо при переводе строк в числа). Форматирование, в частности, описывает режим представления чисел.
Кроме того, эта техника позволяет реализовать функциональность функций типа printf, создающих строку с внедренными туда данными. Нечто вроде интерполяции в смысле языка Perl.
Вот идиома языка: получение числового параметра из командной строки.
integer:: p = 0 ! числовой параметр с значением по умолчанию
character(len=8):: s ! строка
if(command_argument_count()>0) then ! если хотя бы 1 аргумент командной строки присутствует,
call get_command_argument(1,s) ! получаем первый из них в исходящем параметре s
read(s, *) p ! и читаем число из строки
end if
Описание формата - это, по сути, узкоспециализированный язык описания текстового представления данных. Он позволяет выводить текст, управлять положением "головки", читающей либо пишущей очередной объект данных или символ, а также определять текстовое представление числа, включая точность округления и ряд свойств, задаваемых также и спецификаторами операторов ввода/вывода (десятичная точка, способ округления и т.п.) Для примера: дескриптор I (латинская заглавная i, регистр, кстати, не важен) означает, что очередной объект данных целочисленный, и определяет текстовое представление этого числа. После дескриптора указывается ширина поля в символах, а через точку может быть указано минимальное число символов. Так, дескриптор I3 предписывает вывести число, выделив на это три символа. Если число короче, то лишние символы будут пустыми. А I3.3 предписывает вывести трехзначное положительное или двузначное отрицательное число - если число меньше, выводятся лидирующие нули. Есть дескрипторы для ввода/вывода целых в двоичной, восьмеричной и шестнадцатеричной системах счисления. Интереснее обстоит дело с вводом/выводом вещественных чисел. Дескриптор F определяет ширину поля и число символов дробной части (разделенные точкой), то есть, опосредованно, точность. Дескрипторы E и D описывают число с экспонентой, типа 2E3 = 2000. при этом указывается ширина поля, число символов дробной части и, необязательно, число цифр в экспоненциальной части, отделенные символом E. Дескриптор D отличается только тем, что в изображении числа экспонента обозначается символом D вместо E: 6.66D2 = 666. Это намекает на двойную точность - DOUBLE. Дескрипторы EN и ES описывают число в инженерной и научной нотации: десятичный порядок кратен трем, а значащая часть по модулю не меньше единицы и меньше тысячи (либо нуль), либо значащая часть по модулю не меньше единицы и меньше десяти (либо нуль). Дескриптор L описывает логические данные, а A - символьные. Существует обобщенный дескриптор G, способный описывать данные любого встроенного типа - это нововведение Фортрана весьма удобно. Наконец, дескриптор DT описывает представление данных производных типов с перегруженным вводом/выводом. Управляющие дескрипторы Tn, TLn, TRn и nX служат для изменения позиции выводимого символа: позволяют переписывать символы и, что гораздо полезнее, делать пропуски между изображениями данных. Первый указывает позицию следющего символа, второй и третий - смещение влево или вправо, последний же равносилен третьему. Например, WRITE(1,'(*(I2.2 TR1))') T - здесь формат задан строкой '(*(I2.2 TR1))' и заключен, как предписано, в скобки; бесконечный повторитель * позволяет применить формат (I2.2 TR1) к любому количеству элементов массива T; дескриптор I отводит два символа на число и добавляет нуль к однозначным числам, а TR1 ставит пробел после каждого числа (может быть заменен на 1X). Вообще повторители, в форме целых чисел или символа * перед группой дескрипторов в скобках, играют роль циклов. Текст выводится с помощью дескриптора текста - строки в одиночных или двойных кавычках (имеется в виду текст в формате, а не списке объектов ввода/вывода).
Ряд дескрипторов дублирует спецификаторы операторов ввода/вывода, задающие режимы такового: дескрипторы знака (SS, SP и S), пробелов (BN и BZ), округления (RU, RD, RZ, RN, RC и RP) и десятичной точки (DC и DP). Еще предусмотрены: дескриптор масштаба nP с целым n, конец записи / и конец формата : (двоеточие).
Теперь о спецификаторах операторов форматного ввода/вывода. Оператор OPEN: ACCESS - режим доступа к файлу, для форматных обычно SEQUENTIAL, это значение по умолчанию; ACTION - ДОСТУП ДЛЯ ЧТЕНИЯ ЛИБО ЗАПИСИ (READ, WRITE, READWRITE); ENCODING - задает кодировку (UTF8 или DEFAULT); FILE - имя файла; FORM - форматность (FORMATTED, UNFORMATTED, STREAM); RECL - для форматных файлов задает максимальную длину записи (строки); STATUS - определяет статус файла (новый NEW, при этом файл не должен существовать, старый OLD, файл обязан присутствовать, наличие не существенно REPLACE, при котором файл создается или перезаписывается, временный SCRATCH, при котором имя не указывается, а определяется системой, файл автоматически удаляется, и неизвестный UNKNOWN, при котором статус определяет система; UNIT - устройство, целое число, в том числе переменная; NEWUNIT - указывает переменную, в которую заносится номер устройства, подбираемого системой. Это спецификаторы, описывающие файл. Кроме того: BLANK регламентирует трактовку пробелов при вводе численных значений: игнорирование пробелов (значение 'NULL', оно задано по умолчанию) или интерпретация их как нулей (значение 'ZERO'). Влияет только на ввод. DECIMAL определяет десятичный разделитель: точка или запятая. Значения, соответственно, 'COMMA' и 'POINT' (по умолчанию). DELIM определяет разделитель десятичных разрядов: кавычка, апостроф или отсутствие такового. Возможные значения описателя 'QUOTE', 'APOSTROPHE' и 'NONE' (по умолчанию). Влияет только на вывод. PAD определяет действия в случае, если оператор форматного ввода запрашивает больше символов, чем содержит запись. Если значение 'YES' (по умолчанию), вместо недостающих символов подаются пробелы. Если значение 'NO', возникает ошибочная ситуация. На вывод не влияет. ROUND определяет режим округления при форматном вводе/выводе. Возможные значения: 'UP', 'DOWN', 'ZERO', 'NEAREST', 'COMPATIBLE' или 'PROCESSOR_DEFINED'. Значение по умолчанию зависит от системы. Необходимость в округлении связана с разницей представления чисел в двоичной (внутренней) форме и десятичной (читаемой из файла) форме. Кратко опишем режимы по порядку: принимается наименьшее из допустимых чисел, превосходящих (или равных) данному десятичному; наибольшее из допустимых, не превосходящих данного; ближайшее значение к данному числу, по модулю не превосходящее данного числа; ближайшее из двух ближайших, если расстояние от них различно, а если два ближайших равноудалены, то выбор зависит от системы; ближайшее из двух ближайших, если расстояние от них различно, а если два ближайших равноудалены, то более отдаленное от нуля; в последнем случае способ округления определяется системой. SIGN определяет способ записи чисел со знаком (точнее, определяет, ставить ли необязательный знак «плюс» перед положительными числами). Значения таковы: 'PLUS', 'SUPPRESS' и 'PROCESSOR_DEFINED' (по умолчанию), то есть «ставить всегда», «не ставить никогда» и системно-зависимое решение. Еще предусмотрены спецификаторы ERR - задает метку строки, на которую следует перейти в случае ошибки. IOSTAT задает скалярную целочисленную переменную, в которую заносится код ошибки операции ввода/вывода: нуль в случае успеха; положительное число, описывающее ошибку; или отрицательное число, если ошибки не было, но встретилась запись «конец файла». Встроенные функции IS_IOSTAT_END и IS_IOSTAT_EOR (стандартные) позволяют проверить, означает ли код, что встретилась ситуация «конец файла» или «конец записи» (этот спецификатор применяется со многими операторами ввода/вывода, но не все коды применимы к каждому). IOMSG задает скалярную символьную переменную (строку), в которую заносится текстовое сообщение об ошибке; если ошибки не было, значение переменной не меняется. Операторы READ, WRITE, PRINT могут отменять режимы, заданные при открытии файла, с помощью спецификаторов BLANK, DECIMAL, DELIM, PAD, ROUND, SIGN. СпецификаторыEND и EOR задают метку строки, на которую следует перейти в ситуации «конец файла» и «конец записи» соответственно. EOR требует спецификатор ADVANCE (устанавливает, перемещать ли позицию на следующую запись при чтении или записи текущей записи.) со значением 'NO'. ERR, IOSTAT, IOMSG аналогичны одноименным спецификаторам оператора открытия файла OPEN. SIZE задает целую переменную, которой присваивается число введенных символов при синхронном вводе (при асинхронном -- по завершении соответствующей ситуации ожидания). Требует спецификатор ADVANCE со значением 'NO'. Обязателен спецификатор UNIT (целое число или переменная, символ * или текстовая переменная - внутренний файл) и либо FMT (задает формат в виде строки, метки оператора FORMAT или символа *), либо NML (задает имя списка ввода/вывода).