современный фортран , Бортеньев. О. В. Бартеньев Современный Фортран
Скачать 2.24 Mb.
|
Замечание. Для управления выводом можно использовать СИ-символы: '\n'c - новая строка, '\r'c - возврат каретки, '\t'c - табуляция и др. (разд. 3.5.5). Например: character(4) year(5) /'1998', '1999', '2000', '2001', '2002'/ write(*, *) 3.55, '\t'c, 'pels', '\n\r'c, (year(i),' ', i = 1,5) Результат: 3.550000 pels 1998 1999 2000 2001 2002 326 10. Файлы Фортрана 10.1. Внешние и внутренние файлы В Фортране различают два вида файлов: внешние и внутренние. Внешний файл - файл, существующий в среде, внешней по отношению к выполняемой программе. Внутренние файл - символьная строка (подстрока) или массив. Внутренние файлы являются открытыми по умолчанию. Внешние файлы должны быть открыты (подсоединены к устройству В/В) оператором OPEN. К файлам Фортрана можно организовать либо последовательный, либо прямой доступ. К некоторым видам файлов - и тот и другой. С внутренними файлами используется только последовательный доступ. Внешние файлы могут быть: • форматными (текстовыми, ASCII); • двоичными (бинарными); • неформатными. Двоичный и неформатный файлы содержат неформатные записи, т. е. записи, создаваемые без преобразования данных. Файл не может одновременно содержать форматные и неформатные записи. Внешние файлы могут быть открыты как для монопольного, так и для разделенного (сетевого) доступа. Можно создать временный (scratch) внешний файл, который будет удален с физического устройства либо после его закрытия, либо при нормальном завершении программы. При разделенном доступе внешний файл можно заблокировать (сделать недоступным для другого процесса). 10.2. Позиция файла В результате выполнения операции над внешним файлом он может находиться: • в начальной точке файла - непосредственно перед первой записью; • между соседними записями файла; • в пределах одной записи; • в конечной точке файла - после последней записи до специальной записи "конец файла"; • на записи "конец файла"; • после специальной записи "конец файла". Факт перемещения на "конец файла" устанавливается функцией EOF, которая возвращает .TRUE., если файл позиционирован в конце файла или вслед за ним, и .FALSE. - в противном случае. 327 О. В. Бартеньев. Современный ФОРТРАН Файл оказывается после записи "конец файла", если в результате выполнения оператора READ возникла ситуация "конец файла". Файл не должен быть установлен после записи "конец файла" перед началом передачи данных. Для изменения ситуации в файлах с последовательным доступом употребляются операторы REWIND или BACKSPACE. 10.3. Устройство ввода/вывода Для передачи данных файл Фортрана подсоединяется к устройству В/В. Устройство внешнего файла задается целочисленным скалярным выражением или звездочкой (*). Возвращаемый им результат называется номером устройства В/В, значение которого должно находиться в интервале от 0 до 32767. Устройство внутреннего файла задается переменной стандартного символьного типа. Устройство используется для ссылки на файл. Кроме файлов к устройствам В/В могут быть подсоединены физические устройства, например клавиатура, экран, принтер, параллельный порт. Всегда в каждой Фортран-программе существуют устройства *, 0, 5 и 6. Причем по умолчанию к устройствам *, 0 и 5 подсоединена клавиатура, а к устройствам *, 0 и 6 - экран. Так, в программе real :: b = 1.2 write(*, '(F6.2)') b write(0, '(F6.2)') b write(6, '(F6.2)') b end все операторы WRITE обеспечат вывод значения переменной b на экран. Внешний файл подсоединяется к устройству В/В в результате выполнения оператора OPEN. После подсоединения и устройство и файл считаются открытыми. Доступ к внешнему файлу, после того как он открыт, выполняется по номеру устройства, к которому он подсоединен: все программные компоненты, ссылающиеся на одно и то же устройство, ссылаются на один и тот же файл. Аналогом такого номера являются в СИ указатель на файл, в Паскале - файловая переменная. Пример: integer :: k = 2, m = 4 ! Устройство В/В - целочисленное скалярное выражение open(k * m, file = 'd:\a.txt') ! Файл d:\a.txt подсоединен к устройству 8 open(m / k, file = 'd:\b.txt') ! Файл d:\b.txt подсоединен к устройству 2 write(8, '(i8)') k ! Пишем в файл d:\a.txt write(m - k, '(i2)') m ! Пишем в файл d:\b.txt close(8) ! Закрываем устройство 8 и файл d:\a.txt close(k) ! Закрываем устройство 2 и файл d:\b.txt 328 10. Файлы Фортрана Одно и то же устройство В/В в любой программной единице выполняемой программы ссылается на один и тот же файл, например: program fOpen integer, parameter :: n = 9 open(n, file = 'a.txt') ! Подсоединяем файл a.txt к устройству 9 write(n, *) 'Test string' ! Формируем одну запись в файле a.txt call ReadFileData( ) ! Читает первую запись файла a.txt end program fOpen subroutine ReadFileData( ) ! В подпрограмме устройство 9 ссылается на character(30) :: st ! файл a.txt rewind 9 ! Переход на начало файла a.txt read(9, '(a)') st ! Читаем первую запись файла a.txt print *, st ! Test string end subroutine ReadFileData Устройство не может быть одновременно подсоединено более чем к одному файлу, также и файл не может быть одновременно подсоединен более чем к одному устройству. 10.4. Внутренние файлы Различают два основных типа внутренних файлов: • символьную скалярную переменную, элемент символьного массива, символьную подстроку. Каждый такой файл имеет одну запись, длина которой совпадает с длиной образующего файл символьного элемента; • символьный массив. Число записей такого файла совпадает с числом элементов символьного массива. Длина записи файла равна длине элемента символьного массива. Для передачи данных во внутренний файл употребляются операторы WRITE и READ. При этом можно использовать как форматный В/В, так и В/В под управлением неименованного списка. Перед исполнением оператора В/В внутренние файлы всегда позиционируются в начало файла. Внутренние файлы после их создания всегда открыты как для чтения, так и для записи. Устройством внутреннего файла является имя строки, подстроки, символьного массива или его элемента. Часто внутренние файлы применяются для создания строк, содержащих смесь символьных и числовых данных (разд. 3.8.7), а также для простых преобразований "число – строка" и "строка – число", например: real :: a = 234.55 integer kb character(20) st write(st, *) a ! Преобразование "число – строка" print *, st ! 234.550000 ! Для FPS: 329 О. В. Бартеньев. Современный ФОРТРАН read(st, '(i8)') kb ! Преобразование "строка – число" ! Для CVF: read(st, '(i5)') kb ! Преобразование "строка – число" print *, kb ! 23 end 10.5. Внешние файлы Внешние файлы характеризуются приводимыми ниже понятиями. Тип записи определяет, имеют ли записи файлов одинаковую длину, или они могут быть разной длины, или задает способ определения конца одной записи и начала другой. Доступ к файлу определяет метод, используемый при чтении и записи данных, независимо от их организации. Способ организации файла не всегда определяет метод доступа к его записям. CVF поддерживает два вида организации файла: последовательную и связанную. В CVF организация задается спецификатором ORGANIZA- TION оператора OPEN. Файлы, имеющие связанную организацию, сохраняются на диске, последовательную - как на диске, так и на магнитной ленте. Все иные периферийные устройства, такие, как терминалы или принтеры, рассматриваются Фортраном как файлы с последовательной организацией. Замечание. Файлы со связанной организацией мы будем также называть связанными файлами. Последовательно организованный файл состоит из записей, расположенных в порядке их поступления в файл. В связанных файлах записи имеют одинаковую длину и хранятся в так называемых ячейках. Каждая ячейка имеет номер из диапазона [1, n], где n - номер последней доступной ячейки. Номер ячейки - это номер записи, исчисляемый относительно начала файла. В CVF для удаления записи связанного файла употребляется оператор DELETE. Фортран поддерживает два метода доступа к внешнему файлу: последовательный и прямой - и 3 структуры файлов: форматную, неформатную и двоичную. Поэтому можно создать файлы: • форматные последовательные; • форматные прямые; • неформатные последовательные; • неформатные прямые; • двоичные последовательные; • двоичные прямые. 330 10. Файлы Фортрана Замечание. Файлы, подсоединенные для прямого доступа, мы будем, для сокращения, также называть прямыми файлами, а для последовательного доступа - последовательными. В последовательных файлах существующие записи могут только читаться, но не могут редактироваться. Без потери информации новые записи добавляются только после последней записи файла. Попытка вывести запись до этой записи приведет к отсечению последующих записей - их замене на добавляемую. Для изменения записи последовательного файла возможен такой путь: прочитать все записи файла в массив; изменить в нем нужную запись; перейти на начало файла и записать массив в файл. В прямых файлах доступ к записи выполняется по номеру записи, задавая который можно читать, добавлять, замещать или удалять запись. В этом и состоит основное отличие между последовательными и прямыми файлами. При включении спецификатора REC в операторы передачи данных и управления файлами прямой файл позиционируется вслед за указанной этим спецификатором записью. Для внешних файлов справедливо: • для обеспечения доступа файл должен быть открыт (подсоединен к устройству В/В); • при открытии файла по умолчанию он позиционируется на первую запись файла или на "конец файла", если в файле нет ни одной записи; • последней записью файла является специальная запись "конец файла". 10.6. Записи 10.6.1. Типы записей Запись - это последовательность значений (в случае неформатных и двоичных файлов) или последовательность символов (в случае форматных файлов). Поле записи - часть записи, содержащая данные, которые могут быть использованы оператором ввода. Тип записи определяет способ хранения полей в пределах записи. Тип записи не сохраняется как атрибут файла. Однако применение с файлом типа записи, отличного от используемого при создании файла, может привести в некоторых случаях к непредсказуемым результатам. Запись является текущей, если файл установлен внутри записи, в противном случае текущей записи нет. Если опущена опция компилятора /fpscomp:ioformat, в CVF доступны следующие 6 типов записей: 1) фиксированной длины. Такие записи возможны в файлах и с последовательной и со связанной организацией; 2) переменной длины; возможны только в файлах с последовательной организацией; 331 О. В. Бартеньев. Современный ФОРТРАН 3) сегментированные; возможны только в файлах с последовательной организацией, открытых для неформатного последовательного доступа. Сегментированные файлы являются прерогативой CVF и не могут быть использованы другими платформами; 4) потоки без разделителей между записями; возможны только в файлах с последовательной организацией; 5) CR-потоки; используют CR (CHAR(13), carriage return) в качестве разделителя между записями; употребляются в файлах с последовательной организацией; 6) LF-потоки; используют CR и LF (CHAR(10), line feed) в качестве разделителей между записями; применяются в файлах с последовательной организацией. 10.6.2. Записи фиксированной длины Записи фиксированной длины имеют приведенную на рис. 10.1 структуру. Данные записи <-------------------- Длина записи (RECL = recl) ----------------------> Рис. 10.1. Структура записи фиксированной длины Записи фиксированной длины имеют связанные файлы и файлы с последовательной организацией, открытые для прямого доступа. Длина записи задается в операторе OPEN спецификатором RECL. Пример: type point real x, y end type point integer i type(point) :: pt1 = point(1.0, 1.0), pt2 = point(2.0, 2.0), pt3 = point(3.0, 3.0) open(1, file = 'a.txt', organization = 'sequential', access = 'direct', & form = 'formatted', recordtype = 'fixed', recl = 20) write(1, '(2f10.3)', rec = 1) pt1 ! Заносим в файл 3 записи write(1, '(2f10.3)', rec = 2) pt2 ! Спецификатор RECORDTYPE = 'FIXED' write(1, '(2f10.3)', rec = 3) pt3 ! может быть опущен end Результат (состав файла a.txt): 1.000 1.000 2.000 2.000 3.000 3.000 Замечание. Пример справедлив только для CVF, поскольку в операторе OPEN FPS спецификатор ORGANIZATION появляться не может. 332 10. Файлы Фортрана 10.6.3. Записи переменной длины Такие записи могут содержать произвольное число байт (не превышающее максимально возможное значение). Их структура отображена на рис. 10.2. Данные записи 4 <-------------------------- Длина записи ---------------------------> 4 Рис. 10.2. Структура записи переменной длины Записи переменной длины могут существовать только в файлах с последовательной организацией. Каждая запись обрамляется 4-байтовыми полями, содержащими длину записи и выполняющими контрольные функции. Хранимая в этих полях величина возвращается при использовании оператора READ с дескриптором управления Q (разд. 9.8). Прочитанное значение можно затем употребить для определения размера списка В/В. В CVF файлы с записями переменной длины обычно не используются как текстовые файлы, для которых, как правило, задается спецификатор RECORDTYPE = 'STREAM_LF'. Пример: integer recl open(2, file = 'a.txt', recordtype = 'variable', form = 'unformatted') ! Заносим в файл 3 записи write(2) 123, 555 ! Длина записи 8 байт write(2) 'Next record' ! Длина записи 11 байт write(2) 1.4e-6 ! Длина записи 4 байта close(2) ! Закрыли файл, чтобы открыть его для форматного доступа ! и прочитать длину второй записи open(2, file = 'a.txt', recordtype = 'variable', form = 'formatted') ! Спецификатор FORM = 'FORMATTED' может быть опущен read(2, '(a)') ! Переход на начало второй записи read(2, '(Q)') recl ! Читаем число байт в записи 2 print *, recl ! 11 end 10.6.4. Сегментированные записи Сегментированные записи состоят из одной или более переменной длины неформатных записей в последовательно организованном дисковом файле. В FPS таких записей нет; в CVF по умолчанию неформатные данные записываются в файлы с последовательной организацией, открытые для последовательного доступа, в виде сегментированных записей. Они полезны при работе с длинными записями, в случаях, когда нет возможности (из-за ограничений по размеру виртуальной памяти) или желания формировать одну длинную запись. Тогда она разбивается на 333 О. В. Бартеньев. Современный ФОРТРАН сегменты, которые и образуют результирующую запись. Каждый сегмент является физической записью, а результирующая запись рассматривается как единая логическая. Последняя (в случае дискового файла) может превышать максимально допустимый размер записи (2.14*10 9 байт), но каждый сегмент не должен быть больше этого размера. Для доступа к сегментированному файлу задаются спецификаторы FORM = 'UNFORMATTED' и RECORDTYPE = 'SEGMENTED'. Если они не заданы и открывается ранее созданный сегментированный файл, то работа с ним может сопровождаться ошибками. Структура сегментированной записи представлена на рис. 10.3. Данные сегмента 2 2 <------------------------- Длина сегмента -------------------------> Рис. 10.3. Структура сегментированной записи Контрольная информация, предваряющая запись, содержит 4 байта. Первые два содержат длину сегмента, два последующих - идентификатор сегмента, принимающий значения: • 1 в случае первого сегмента; • 2 в случае последнего; • 3 при наличии одного сегмента; • 0 для всех промежуточных (между первым и последним) сегментов. Если длина сегмента - нечетное число, то пользовательские данные будут увеличены на 1 байт, содержащий пробел. 10.6.5. Потоки Поток не группируется в записи и не содержит контрольной информации. Файлы-потоки применяются с CARRIAGECONTROL = 'NONE' и содержат символьные или двоичные данные. Передаваемая порция данных и позиция файла определяются размером списка В/В. Структура потока дана на рис. 10.4. Данные потока EOF Рис. 10.4. Поток 10.6.6. CR-потоки Записи CR-потока имеют переменную длину и завершаются символом возврата каретки, который автоматически проставляется при добавлении записи в файл-поток и удаляется при ее чтении. Именно этот символ и позволяет определить длину текущей записи. Поскольку CR-потоки завершаются символом CHAR(13), в вводимых записях этот символ должен отсутствовать. Структура записи CR-потока изображена на рис. 10.5. 334 10. Файлы Фортрана Данные записи CR <-------------------------- Длина записи ---------------------------> 1 Рис. 10.5. Запись CR-потока Пример: integer recl open(3, file = 'a.txt', recordtype = 'stream_cr') ! Заносим в файл 3 записи; он открыт как текстовой (форматный) файл ! В случае вывода под управлением списка оператор WRITE вставляет ! в начало каждой записи пробел write(3, *) 123, 555 ! Длина записи 24 байта (см. разд. 9.9.2.2) write(3, *) 'Next record' ! Длина записи 13 байт write(3, *) 1.4e-6 ! Длина записи 16 байт backspace(3) ! Возврат на одну запись read(3, '(Q)') recl ! Читаем число байт в третьей записи print *, recl ! 16 end Результат (состав файла a.txt): 123 555 Next record 1.4000000E-06 10.6.7. LF-потоки Записи LF-потока имеют переменную длину и завершаются символами возврата каретки и новой строки, которые автоматически проставляются при добавлении записи и удаляются при чтении. Эти символы позволяют определить длину текущей записи. Поскольку LF-потоки завершаются символами CHAR(13) и CHAR(10), в вводимых записях эти символы должны отсутствовать. LF-потоки - это стандартные текстовые файлы. Структура записи LF-потока представлена на рис. 10.6. Данные записи CR LF <-------------------------- Длина записи ---------------------------> 1 1 Рис. 10.6. Запись LF-потока Пример: integer recl open(4, file = 'a.txt', recordtype = 'stream_lf') ! Заносим в файл 3 записи; он открыт как текстовой (форматный) файл write(4, '(2i5)') 123, 555 ! Длина записи 10 байт write(4, '(a30)') 'Next record' ! Длина записи 30 байт |