современный фортран , Бортеньев. О. В. Бартеньев Современный Фортран
Скачать 2.24 Mb.
|
335 О. В. Бартеньев. Современный ФОРТРАН write(4, '(e20.8)') 1.4e-6 ! Длина записи 20 байт rewind(4) ! Переход на начало файла read(4, '(Q)') recl ! Читаем число байт в третьей записи print *, recl ! 10 end Результат (состав файла a.txt): 123 555 Next record 0.14000000E-05 10.7. Передача данных с продвижением и без Оператор В/В с продвижением всегда устанавливает файл после последней считанной или записанной записи (если не было ошибок). Оператор В/В без продвижения, применяемый при форматной передаче данных и задаваемый спецификатором ADVANCE = 'NO' или (при выводе) дескрипторами \ и $, может устанавливать файл внутри текущей записи. Используя такой оператор, можно прочитать или записать одну запись с помощью нескольких операторов В/В, причем каждый из них будет обращаться к части записи, например: character(6) :: st1, st2 open(1, file = 'a.txt') write(1, *) 'Test string' ! Вывод с продвижением rewind 1 ! Переход на начало файла read(1, '(a6)', advance = 'no') st1 ! Ввод без продвижения print *, st1 ! Test read(1, '(a6)', advance = 'no') st2 ! Ввод второго слова в ту же запись print *, st2 ! string 10.8. Позиция файла перед передачей данных Порядок установки позиции файла перед передачей данных зависит от способа доступа к файлу. В случае последовательного доступа перед вводом, если есть текущая запись, позиция файла не меняется. Иначе файл устанавливается на начало следующей записи и она становится текущей. Ввод запрещен, если нет следующей записи или следующей является запись "конец записи". Такая ситуация в файле с последовательным доступом возникнет, когда последним обратившимся к нему оператором является оператор WRITE. Перед выводом в файл с последовательным доступом, если есть текущая запись, то позиция файла не меняется и текущая запись становится последней записью файла. Иначе, например если файл находился перед записью "конец файла", создается новая запись, в которую будут передаваться данные и которая становится текущей и последней записью файла. Позиция файла устанавливается на начало этой записи. 336 10. Файлы Фортрана При прямом доступе перед передачей данных позиция файла устанавливается в начало записи, определяемой спецификатором оператора В/В REC. Эта запись становится текущей. 10.9. Позиция файла после передачи данных При вводе без продвижения, если не было ситуации ошибки или ситуации "конец файла", но есть ситуация "конец записи", позиция файла устанавливается после только что считанной записи. Если же в операторе ввода без продвижения не было ситуаций ошибки, "конец файла" или "конец записи", то позиция файла не меняется. В операторе вывода без продвижения, если не было ситуации ошибки, позиция файла не изменяется. Во всех остальных случаях файл устанавливается вслед за последней считанной или записанной записью, так что она становится предшествующей записью. 10.10. Двоичные последовательные файлы При работе с двоичными файлами обмен данными выполняется без их преобразования. При записи в двоичный файл в него фактически копируется содержимое ячеек оперативной памяти. При чтении, наоборот, последовательность байтов двоичного файла передается в ячейки оперативной памяти, отведенные под элементы ввода. В FPS число записей в двоичном файле равно числу переданных байт. Поэтому выполнение оператора BACKSPACE приведет к перемещению на 1 байт назад. Последовательный двоичный файл является потоком. Между его записями CVF и FPS не проставляют символов или полей с контрольными данными. Ввод из двоичного файла значения переменной val, занимающей в оперативной памяти n байт, вызовет перемещение файла на n байт. Если последовательный двоичный файл перед выполнением оператора вывода находился на байте b i , то b i и все последующие байты в результате вывода будут "затерты" (заменены на выводимые). Оператор OPEN, подсоединяющий файл к устройству для двоичного последовательного доступа, обязательно включает спецификатор FORM = form, где form - символьное выражение, вычисляемое со значением 'BINARY'. Пример управления двоичным последовательным файлом FPS: integer(2) :: ia, ib, d(5) = (/ 1, 2, 3, 4, 5 /), i real(4) :: a character(3) ca open(1, file = 'a.dat', form = 'binary') ! Открываем двоичный файл write(1) 1.1, 2.2 ! Пишем в файл 8 байт write(1) d ! Добавляем в файл 10 байт write(1) 'aaa', 'bbb', 'ccc' ! Добавим в файл еще 9 байт 337 О. В. Бартеньев. Современный ФОРТРАН rewind 1 read(1) a, a, (ia, i = 1, 5), ca, ca ! Читаем 24 байта одним оператором READ do 2 i = 1, 10 ! Перемещение назад на 10 записей (байт) 2 backspace 1 read(1) ib ! Читаем, начиная с 15-го байта write(*, *) a, ia, ca, ib ! 2.200000 5bbb 4 rewind 1 read(1) a ! Файл переместился на 5-й байт write(1) 'ghi' ! Заменены 5, 6 и 7-й байты; rewind 1 ! все последующие записи "затерты" read(1) a, ca write(*, *) a, ca ! 1.100000ghi (в файле 7 байт данных) end Замечания: 1. В CVF при работе с двоичными файлами оператор BACSPACE либо вызывает ошибку исполнения, либо, подобно оператору REWIND, позиционирует файл в его начало, например: character(1) c open(1, file = 'a.dat', form = 'binary') ! Открываем двоичный файл write(1) 'a12', 'b34' ! Добавим в файл 6 байт rewind 1 ! Переход на начало файла read(1) c print *, 'c = ', c ! CVF: c = a ! FPS: c = a rewind 1 ! Переход на начало файла ! Те же действия, но с оператором BACKSPACE write(1) 'a12', 'b34' ! Добавим в файл 6 байт backspace 1 read(1) c print *, 'c = ', c ! CVF: c = a end ! FPS: c = 4 2. Любой внешний файл может быть открыт как двоичный (поток), например с целью копирования данных. 10.11. Неформатные последовательные файлы В неформатные файлы, так же как и в двоичные, данные передаются без преобразований. Однако в неформатном файле в отличие от двоичного записью является не байт, а совокупность данных, выводимых в файл в результате выполнения оператора вывода WRITE. Каждый оператор вывода создает одну запись. Записи файла могут иметь разную длину. Каждая запись завершается символами конца записи. Из неформатного файла одним оператором ввода можно прочитать только одну запись. Попытка такого ввода числа байт, превышающих 338 10. Файлы Фортрана размер текущей записи, приведет к ошибке выполнения и прерыванию программы. Выполнение каждого оператора ввода, даже если число вводимых байт меньше числа байт записи, приведет к позиционированию файла вслед за прочитанной записью. Добавление новой записи при позиционировании файла вслед за записью r i - 1 приведет к удалению записи r i и всех последующих записей (к их замене на добавляемую). Оператор OPEN, подсоединяющий файл к устройству для неформатного последовательного доступа, включает спецификатор FORM = form, где form - символьное выражение, вычисляемое со значением 'UN- FORMATTED'. Пример управления неформатным последовательным файлом: integer(2) :: ia, ib, d(4) = (/ 1, 2, 3, 4 /) real(4) a character(3) ca ! Открываем неформатный файл open(1, file = 'a.dat', form = 'unformatted') write(1) 1.1, 2.2 ! Добавление в файл 1-й записи write(1) d ! Вторая запись write(1) 'aaa', 'bbb', 'ccc' ! Третья запись rewind 1 ! Переход в начало файла read(1) a, a ! Соблюдаем соответствие между read(1) ia, ia, ia, ia ! вводом и выводом read(1) ca, ca backspace 1 ! Переход в начало 3-й записи backspace 1 ! Переход в начало 2-й записи read(1) ib, ib print *, a, ia, ca, ib ! 2.200000 4bbb 2 rewind 1 read(1) a ! Переход в начало 2-й записи write(1) 'ghi' ! Замена 2-й и 3-й записей на ghi rewind 1 read(1) a, a ! В файле осталось 2 записи: read(1) ca ! числа 1.1 и 2.2 и строка ghi print *, a, ca ! 2.200000ghi end 10.12. Текстовые последовательные файлы Текстовой файл содержит символьное представление данных всех типов. При работе с текстовыми файлами используется форматный или управляемый списком В/В. При выводе данные из внутреннего представления преобразовываются во внешнее символьное представление. При вводе происходит обратное преобразование из символьного представления во внутреннее (разд. 9.1). 339 О. В. Бартеньев. Современный ФОРТРАН При выводе в конце каждой записи Фортран проставляет два неотображаемых символа CHAR(13) - возврат каретки и CHAR(10) - новая строка,. То есть записи являются LF-потоками. В случае вывода под управлением списка оператор вывода вставляет в начало каждой записи пробел (по умолчанию первый символ каждой записи форматного файла рассматривается как символ управления кареткой). Записи текстового последовательного файла могут иметь разную длину. Порядок изменения позиции текстового файла с последовательным доступом зависит от способа передачи данных (с продвижением или без, разд. 10.6). При форматном вводе число читаемых одним оператором ввода из текущей записи данных регулируется форматом (разд. 9.4). В отличие от неформатного файла одним оператором ввода в принципе может быть прочитано произвольное число записей текстового последовательного файла. В простейшем случае, открывая текстовой файл для последовательного форматного доступа, можно указать в операторе OPEN только устройство внешнего файла и спецификатор FILE = file. Пример управления текстовым последовательным файлом. (По умолчанию в файлах, открываемых для последовательного доступа, спецификатор FORM = 'FORMATTED'.): integer(2) :: ia, ib, d(4) = (/ 1, 2, 3, 4 /) real(4) a, b character(3)ca 1 format(6f7.2) 2 format(8i5) 3 format(7a4) ! Открываем последовательный текстовой файл a.txt и создаем в нем 3 записи open(10, file = 'a.txt') write(10, 1) 1.1, 2.2 ! Запись 1 write(10, 2) d ! 2 write(10, 3) 'a', 'bc', 'def' ! и 3 ! После выполнения трех операторов вывода в файле будет 3 записи: ! 1.10 2.20 ! 1 2 3 4 ! a bc def rewind 10 ! Переход на 1-ю запись read(10, 1) a, b read(10, 2) ia, ia, ia ! Читаем из 2-й записи ! или вместо двух последних операторов: read(1, *) a, b, ia, ia, ia read(10, 3) ca, ca ! Читаем из 3-й записи backspace 10 ! Переход на начало 3-й записи backspace 10 ! Переход на начало 2-й записи read(10, 2) ib, ib ! Читаем в ib 2-й элемент 2-й записи write(*, *) a, ia, ca, ib ! 1.100000 3 bc 2 rewind 10 ! Переход на начало 1-й записи 340 10. Файлы Фортрана read(10, *) ! Переход на начало 2-й записи write(10, 3) 'ghij' ! Все записи, начиная со 2-й, заменены на ghij ! После выполнения трех последних операторов имеем файл: ! 1.10 2.20 ! ghij end 10.13. Файлы, подсоединенные для прямого доступа Для прямого доступа можно открыть двоичные, неформатные и форматные (текстовые) файлы. В файле, подсоединенном для прямого доступа, все записи имеют одинаковую длину, задаваемую при открытии файла спецификатором RECL. При этом в случае неформатного и текстового файлов число байт, передаваемых одним оператором В/В, не должно превышать длины записи. В случае вывода недостающие байты записи будут содержать null-символы. Необязательно читать или записывать записи по порядку их номеров. В подсоединенный к устройству файл можно занести любую запись. Например, можно записать запись 3, даже если в файле нет записей с номерами 1 и 2. При этом, однако, между началом файла и записью 3 будет зарезервировано пространство для записей 1 и 2: open(1, file = 'a.txt', form = 'formatted', access = 'direct', recl = 7, status = 'new') write(1, '(i7)', rec = 3) 12 ! Добавляем запись 3 Запрещается передавать записи при помощи форматирования под управлением списка (именованного и неименованного). В файле с прямым доступом можно позиционироваться непосредственно вслед за записью r i , выполнив оператор READ, в котором задан спецификатор REC = r i . Список ввода такого оператора может быть пуст. Позиционирование вслед за записью r i в неформатном или двоичном файле: read(2, rec = ri) и в форматном файле: read(2, '(a)', rec = ri) ! Дескриптор формата - любой В CVF для позиционирования прямого файла можно также употребить оператор FIND (разд. 11.8). В файле с прямым доступом при выполнении оператора WRITE будет обновлена та запись, номер которой задан спецификатором REC оператора WRITE. В FPS, если спецификатор REC в операторе WRITE отсутствует, то обновляется текущая запись. Все последующие записи файла будут сохранены. Если же указанная спецификатором REC запись не существует, то она будет добавлена в файл. 341 О. В. Бартеньев. Современный ФОРТРАН Замечание. При работе с прямыми файлами спецификатор REC может отсутствовать только в FPS; для CVF он обязателен. В FPS, чтобы удалить ненужные завершающие записи прямого файла, следует переместиться вслед за последней сохраняемой записью (это обычно выполняется оператором READ), а затем применить оператор ENDFILE. Этот способ в CVF неприменим, поскольку в нем ENDFILE работает только с последовательными файлами. Оператор OPEN, подсоединяющий файл file для неформатного прямого доступа к устройству u, должен иметь спецификаторы: OPEN(u, FILE = file, ACCESS = 'direct', RECL = recl) где recl - целочисленное выражение, возвращающее длину записи файла. Спецификатор FORM = 'UNFORMATTED' в случае прямого файла задается по умолчанию и может быть опущен. В случае форматного и двоичного файла с прямым доступом спецификатор FORM является обязательным: OPEN(u, FILE = file, ACCESS = 'direct', FORM = 'formatted', RECL = recl) OPEN(u, FILE = file, ACCESS = 'direct', FORM = 'binary', RECL = recl) Пример для FPS. В прямом файле a.dat, содержащем 30 записей, удалить записи, имеющие номер, больший 15. character(30) :: fn = 'a.dat' character(35) :: st = 'One line' integer :: ios, r = 15, ner, i ! Сначала создадим файл из 30 записей open(1, file = fn, access = 'direct', form = 'formatted', recl = 35) endfile 1 ! На тот случай, если файл существует ! Установим файл перед только что проставленной записью "конец файла" rewind 1 write(1, '(a35)') (st, i = 1, 30) ! Теперь в файле 30 записей close(1) open(2, file = fn, access = 'direct', form = 'formatted', & recl = 35, status = 'old', iostat = ios) if(ios .ne. 0) stop 'Cannot open file a.dat' read(2, '(a)', rec = r, iostat = ios) ! Переход в начало записи 16 if(ios .eq. 0) then ! Если удалось прочитать запись r, то проставляем метку конца файла endfile 2 ! В CVF оператор ENDFILE употребляется else ! только с последовательными файлами write(*, *) 'Не могу прочитать запись ', r end if inquire(2, nextrec = ner) ! ner - номер следующей записи print *, ner ! 16 rewind 2 ! Выполним контрольный вывод k = 0 342 10. Файлы Фортрана do while(.not. eof(2)) k = k + 1 ! Номер читаемой записи read(2, '(a)', rec = k) st print *, st, k ! Выведено 15 записей end do end Замечания: 1. Код неприемлем для CVF, поскольку в нем оператор ENDFILE применим только с файлами, открытыми для последовательного доступа. 2. При работе в CVF с файлами с прямым доступом использованный в примере циклический список write(1, '(a35)') (st, i = 1, 30) неприменим, поскольку в CVF при записи в прямой файл оператор WRITE должен содержать спецификатор REC. Поэтому используется цикл do i = 1, 30 ! Цикл приемлем и в FPS и в CVF write(1, '(a35)', rec = i) st end do 3. В файле с прямым доступом CVF в отличие от FPS не проставляет символ новой строки после каждой записи прямого файла. Эта разница иллюстрируется примером: character(30) :: fn = 'a.dat' character(8) :: st = 'A record' open(1, file = fn, access = 'direct', form = 'formatted', recl = 9, status = 'new') write(1, '(a8)', rec = 1) st write(1, '(a8)', rec = 2) st write(1, '(a8)', rec = 3) st end Состав файла a.dat: CVF: A record A record A record FPS: A record A record A record 4. Чтобы установить прямой файл вслед за записью r, можно использовать оператор READ без списка ввода: READ(2, '(A)', REC = r), а в CVF - также оператор FIND, например: FIND(2'r). 5. При работе с текстовыми прямыми файлами возможен только форматный В/В. Передача данных под управлением списка недопустима. Также невозможен и В/В без продвижения. 343 О. В. Бартеньев. Современный ФОРТРАН Файл с записями, переданными в него в режиме прямого доступа, можно впоследствии открыть как двоичный с последовательным доступом (как поток). Пример. В файл, открытый для прямого доступа с RECL = 15, заносятся 3 записи. Затем этот же файл открывается как двоичный для последовательного доступа и данные побайтно переносятся в форматный файл b.txt. Вывод файла b.txt выполняется после его подсоединения с RECL = 15. integer(4), parameter :: n = 15 character(1) c character(n) st integer i 100 format(a ! или: 100 format(a15) open(1, file = 'a.txt', access = 'direct', form = 'formatted', & organization = 'relative', recl = n) ! Создаем в прямом файле 3 записи write(1, 100, rec = 1) 'First record' write(1, 100, rec = 2) 'Second record' write(1, 100, rec = 3) 'Last record' close(1) ! Закрываем файл a.txt ! Файл-источник open(1, file = 'a.txt', form = 'binary') ! Файл-приемник open(2, file = 'b.txt', form = 'formatted', recordtype = 'fixed', recl = 1) do while(.not. eof(1)) ! Копируем данные посимвольно read(1) c ! Читаем 1 байт из источника write(2, '(a)') c ! Пишем 1 байт в приемник end do close(1); close(2) ! Отсоединяем файлы a.txt и b.txt ! Откроем теперь b.txt с RECL = n и прочитаем 3 записи open(2, file = 'b.txt', access = 'direct', form = 'formatted', recl = n) i = 0 ! Номер читаемой записи do while(.not. eof(2)) ! Копируем данные посимвольно i = i + 1 read(2, 100, rec = i) st print *, st ! First record end do ! Second record end ! Last record Отличия между неформатным и двоичным файлами с прямым доступом: • в двоичный файл можно записывать любое число байт, не обращая внимания на значение спецификатора RECL (при этом, правда, длина записи все же определяется спецификатором RECL); • из двоичного файла одним оператором ввода можно считать больше байтов, чем задано спецификатором RECL. |