крывается оператором OPEN, затем производится чтение или запись данных операторами READ или WRITE. После необходимых операций чтения и записи файл закрывается оператором CLOSE с освобождением номера устройства, и освобожденный номер можно использовать для дальнейших файловых операций (пример 3.89).
В результате работы этой программы в текущей директории появится файл «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 – если файл не существует, то он будет создан, а существующий файл, будет удален и создан новый файл с тем же именем;
196
•SCRATCH – создается временный файл, который удаляется после закрытия. Для SCRATCH-файла спецификатор FILE не имеет смысла и не используется;
•UNKNOWN – для существующего файла устанавливает статус OLD, а для несуществующего – статус NEW. UNKNOWN назначается по умолчанию, если спецификатор STATUS явно не прописан в операторе OPEN (см. пример 3.89).
Когда статус файла явно не задан, то при компиляции программы иногда выдается соответствующее предупреждение (warning), которое начинающие программисты часто принимают за ошибку.
Спецификатор ACCESS – способ доступа к данным, определяется скалярным текстовым выражением, принимающим одно из двух значений: SEQUENTIAL (файл последовательного доступа) или DIRECT (файл прямого доступа). Файлы прямого доступа состоят из записей одинаковой длины, и к произвольной записи файла можно обратиться по ее номеру. Файлы последовательного доступа могут состоять из записей произвольной длины, а от текущей записи можно перейти только к следующей или предыдущей. Если способ доступа к данным явно не указан (см. пример 3.89), то считается что это файл – последовательного доступа.
Спецификатор RECL – длина одной записи файла (в байтах или машинных словах), актуальна только для файлов прямого доступа.
Спецификатор FORM задается скалярным текстовым выражением и определяет форму представления данных: FORMATTED, соответствующее форматному представлению данных или UNFORMATTED, соответствующее бесформатному представлению данных. Если форма представления не указана, то файл последовательного доступа считается форматным (см. пример 3.89), а файл прямого доступа – бесформатным. Форматный (по сути, текстовый) файл содержит данные в удобочитаемом для человека виде. Эти данные могут считываться и записываться с использованием спецификаций формата. Бесформатный файл не предполагает визуального прочтения и хранит данные во внутреннем машинном представлении.
Спецификатор IOSTAT характеризует состояние ввода/вывода и задается как любая целая скалярная переменная, например IOSTAT= IOS, при этом IOS = 0 означает успешную операцию ввода/вывода, а любое другое значение констатирует ошибку.
197
Для предъявления оператора OPEN в развернутом виде целесообразно разделить пример 3.89 на две части (примеры 3.90 и 3.91).
Пример 3.90. Оператор 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
Если при запуске программы (см. пример 3.90) в текущей директории присутствует файл INFO.txt с явно указанным для него статусом NEW в операторе OPEN, то программа завершится по ошибке: «IOS > 0». Файл INFO.txt является результатом работы программы и должен появиться после ее запуска.
Пример 3.91. Открытие, запись, чтение и закрытиефайлов 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
Для корректной работы программы (см. пример 3.91) требуется наличие в текущей директории файла INFO.txt – результата работы предыдущего примера. Если такого файла не окажется, то программа завершится с ошибкой: «IOS > 0», поскольку для файла данных INFO.txt явно указан статус OLD в операторе OPEN.
В операторах READ и WRITE при работе с текстовыми файлами могут использоваться все дескрипторы формата ввода/вывода дан-
198
ных (см. п. 3.6.3). Однако помимо номера устройства и спецификации формата, операторы READ и WRITE могут содержать и другие спецификаторы, например спецификатор IOSTAT в точности такой же, как для оператора OPEN.
Наличие спецификатора IOSTAT в операторах READ и WRITE позволяет программисту самостоятельно обрабатывать ошибки чтения и записи в штатном режиме, без прерывания работы программы. Это может быть весьма актуально при обработке текстовых файлов с заранее неизвестным количеством текстовых строк, например при копировании одного файла в другой (пример 3.92).
Для работы этого примера в текстовом редакторе потребуется подготовить небольшой текстовый файл с именем FILE1.txt, в котором не менее трех строк, каждая не длиннее 80-ти символов. На выходепрограмма создаст копию файла FILE1.txt в файлес именем
FILE2.txt.
Пример 3.92. Копирование файлов 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 – перейти к началу файла. В качестве параметра оба оператора используют номер ассо-
199
циированного с файлом устройства, например BACKSPACE 1 или REWIND 4. Если файл уже позиционирован в начало, то применение этих операторов не повлечет за собой ошибки или изменения в позиционировании. Проиллюстрировать возможности позиционирования можно на своеобразном «плеере» файла с элементами «перемотки» записей (пример 3.93). Для работы программы потребуется текстовый файл с именем FILE1.txt, с несколькими строками, не длиннее 80-ти символов.
Пример 3.93. «Перемотка записей» текстовогофайла 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») выходит за рамки данного учебного пособия.
200