Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
современный фортран , Бортеньев.pdf
Скачиваний:
242
Добавлен:
26.03.2015
Размер:
2.34 Mб
Скачать

 

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

Запрещается передавать записи при помощи форматирования под управлением списка (именованного и неименованного).

В файле с прямым доступом можно позиционироваться непосредственно вслед за записью ri, выполнив оператор READ, в котором задан спецификатор REC = ri. Список ввода такого оператора может быть пуст.

Позиционирование вслед за записью ri в неформатном или двоичном файле:

read(2, rec = ri)

и в форматном файле:

read(2, '(a)', rec = ri) ! Дескриптор формата - любой

ВCVF для позиционирования прямого файла можно также употребить оператор FIND (разд. 11.8).

Вфайле с прямым доступом при выполнении оператора WRITE будет обновлена та запись, номер которой задан спецификатором REC оператора WRITE. В FPS, если спецификатор REC в операторе WRITE отсутствует, то обновляется текущая запись. Все последующие записи файла будут сохранены. Если же указанная спецификатором REC запись не существует, то она будет добавлена в файл.

341

! ner - номер следующей записи
! 16 ! Выполним контрольный вывод
342

О. В. Бартеньев. Современный ФОРТРАН

Замечание. При работе с прямыми файлами спецификатор 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) print *, ner

rewind 2 k = 0

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

Arecord

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<n>)

! или: 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.

344

! 3
! C12-92 C16-99
! Прочитать 14 байт из неформатного файла, ! открытого с RECL = 8, нельзя

10. Файлы Фортрана

Один и тот же двоичный или неформатный файл может быть открыт с разными значениями спецификатора RECL.

Пример:

character(14) ch integer ner

open(2, file = 'a.bin', access = 'direct', form = 'binary', recl = 8) write(2, rec = 1) 'C12-', '92' ! Пишем в файл 8 байт

write(2, rec = 2) 'C16-', '99' ! Вторая запись двоичного файла

! Читаем 14 байт из двоичного файла, т. е. больше, чем задано RECL read(2, rec = 1) ch

inquire(2, nextrec = ner) print *, ner

write(*, *) ch end

Приведенный текст в FPS может выглядеть так:

character(14) ch integer ner

open(2, file = 'a.bin', access = 'direct', form = 'binary', recl = 8)

write(2) 'C12-', '92'

! Пишем в файл 8 байт

write(2) 'C16-', '99'

! Вторая запись двоичного файла

rewind 2

 

read(2) ch

! Читаем 14 байт из двоичного файла

inquire(2, nextrec = ner)

 

print *, ner

! 3

write(*, *) ch

! C12-92 C16-99

end

В CVF этот код неприменим, поскольку, во-первых, операторы В/В не содержат спецификатор REC, а во-вторых, использован оператор REWIND, который в CVF употребляется только с последовательными файлами.

В FPS текстовой прямой файл устроен так же, как и текстовой последовательный файл, в котором все записи имеют одинаковую длину. Поэтому текстовой файл с равными по длине записями может быть открыт в FPS как для прямого, так и для последовательного доступа.

Пример. В текстовом файле, подсоединенном для прямого доступа, каждая запись имеет поля "Фамилия И. О.". По ошибке в некоторых записях фамилия начинается со строчной буквы. Исправить ошибку в исходном файле и сформировать отчет в виде двоичного файла, содержащего исправленные записи.

integer(4), parameter :: n = 15 type person

character(len = n) lastn, firstn end type person

345