Fortran中的文件处理(初级)
简述
在Fortran程序中使用文件,需要一些选择所需文件和读写该文件的方法,该机制称为输入/输出单元(I/O单元)。
READ(* , *)
和WRITE(* , *)
语句中的第一个*
号与 I/O单元 相对应。当*
号被 I/O单元号 代替时,程序对应的读和写将指向该单元指定的设备,替代预定标准的输入或输出设备。
- I/O单元号必须为整数类型;
- I/O单元号为 5 预定义为程序的标准输入设备(即键盘),为 6 预定义为程序的标准输出设备(即显示器),此时用
*
号表示。
常用的语句有:
I/O 语句 | 用途 |
---|---|
OPEN | 将一个文件与一个给定的I/O单元号关联起来 |
CLOSE | 关闭一个文件并释放与之关联的I/O单元号 |
REWIND | 倒回文件,一般用于倒回临时文件 |
语句
1) OPEN
-
语句:
OPEN( open_list )
,其中open_list
是一组子句,分别指定I/O单元号、文件名和关于如何存取文件的信息。特性:- 子句的顺序可以是任意;
- 子句用逗号
,
隔开。
-
open_list
含有许多子句,最重要的主要有以下六项:UNIT = int_expression
,指明与文件关联的I/O单元号,int_expression
为非负的整数值;FILE = char_expression
,指定要打开的文件名,char_expression
为文件名称的字符值;STATUS = char_expression
,指定要打开文件的状态,char_expression
的取值为下列中的一个:OLD
,NEW
,REPLACE
,SCRATCH
或UNKNOW
;ACTION = char_expression
,指定文件以读或写的方式打开,char_expression
的取值为下列中的一个:READ
,WRITE
或READWRITE
,如未指定则是以读写方式打开;IOSTAT = int_variable
,指定一个整数变量名,把打开操作的状态返回到这个int_variable
变量中。如果OPEN
语句成功执行,则整数变量int_variable
的值为0,其它数值则是未成功执行(不同处理器,相应系统错误信息会不同);IOMSG = char_variable
,指定一个字符变量名。如果OPEN
语句成功执行,字符变量char_variable
的内容不会变化,如没成功执行,一个描述错误的信息将返回到该字符串中。
2) CLOSE
语句:CLOSE( close_list )
,close_list
必须包含一个指定I/O单元号的子句,还可以指定其它选项。特性:
- 文件关闭后,相关联的I/O单元被释放,可以用
OPEN
将该单元号重新分配给其它任意文件; - 如果程序中没有包含对给定文件的
CLOSE
语句,这个文件将在程序结束时被自动关闭。
3) READ语句中添加子句
在使用READ
语句时,可以添加IOSTAT = int_variable
和 IOMSG = char_variable
子句,检查是否发生读取错误,并返回相应信息,而不引起程序异常中断。
-
IOSTAT = int_variable
,- 当
READ
语句成功执行时,int_variable
的值为0; - 当
READ
语句执行失败,如读取的变量不符合所定义类型时,int_variable
的值为与系统错误信息相对应的正数; - 当
READ
语句执行至数据文件的尾部时,语句会执行失败,int_variable
的值为负数。
- 当
-
IOMSG = char_variable
,当IOSTAT
变量值为非0时,IOMSG
会已语句形式返回字符串来解释发生的错误。
注意:当从文件中读取数据时,READ
语句应总是包含IOSTAT
子句,使得程序可以检查所读取的数据是否符合要求(如类型判断),以及避免读取文件结尾之外行信息时的异常中断。
-
具体例子:现有一个数据文件,有多行,每一行中有1个数据,数据类型是实数型,通过输入文件名来获取其中的数据,输出内容为实数数据及其对应行号,并交代总行数(即数据个数)。同时,需要能够返回数据读取失败时的信息提醒,以及文件打开错误时的信息提醒。
代码如下:PROGRAM read_file IMPLICIT NONE CHARACTER(len = 20)::filename ! 文件名称 CHARACTER(len = 80)::msg ! 打开文件错误时的异常信息 INTEGER::nvals = 0 ! 读取数据的行数 INTEGER::status1 , status2 ! 打开文件和读取数据的状态信息 REAL::value ! 需读取文件中的数据 WRITE(*,*) 'Please enter input file name' ! 读取需要打开的文件 READ(*,*) filename WRITE(*,1000) filename 1000 FORMAT('The input file name is: ' , A) OPEN(UNIT = 3 , FILE = filename , STATUS = 'OLD' , ACTION = 'READ' , IOSTAT = status1 , IOMSG = msg) ! 打开文件 openif:IF(status1 == 0 ) THEN ! 文件打开成功 readloop:DO READ(3 , * , IOSTAT = status2) value IF(status2 /= 0) EXIT ! 如果数据读取失败,跳出DO循环 nvals = nvals + 1 WRITE(*,1010) nvals,value 1010 FORMAT('Line ',I6,' :Value = ',F10.4) END DO readloop readif:IF(status2 > 0) THEN ! 发生了数据读取错误 WRITE(*,1020) nvals+1 1020 FORMAT('An error occurred reading line ',I6) ! 交代在哪一行读取数据失败 ELSE readif ! 到达数据结尾 WRITE(*,1030) nvals 1030 FORMAT('End of file reached.There were ' , I6 , ' values in the file.') ! 交代已经到达文件结尾 END IF readif ELSE openif ! 文件打开失败 WRITE(*,1040) status1 1040 FORMAT('Error opening file : IOSTAT = ',I6) WRITE(*,1050) TRIM(msg) ! 返回错误信息 1050 FORMAT(A) END IF openif CLOSE(UNIT = 3) ! 关闭文件 STOP END PROGRAM read_file
现有正确的数据文件
read1.txt
和错误的数据文件read2.txt
,内容分别是:! read1.txt -15.0 55.333 9.0 4444. -0.02
和
! read2.txt -15.0 55.333 9.0 abc -0.02
运行程序,并分别输入
read1.txt
、read2.txt
和abc.txt
可得:Please enter input file name read1.txt The input file name is: read1.txt Line 1 :Value = -15.0000 Line 2 :Value = 55.3330 Line 3 :Value = 9.0000 Line 4 :Value = 4444.0000 Line 5 :Value = -0.0200 End of file reached.There were 5 values in the file. ! 提示到达数据文件的底部,成功
Please enter input file name read2.txt The input file name is: read2.txt Line 1 :Value = -15.0000 Line 2 :Value = 55.3330 Line 3 :Value = 9.0000 An error occurred reading line 4 ! 提示第4行数据不满足要求
Please enter input file name abc.txt ! 输入不存在的文件 The input file name is: abc.txt Error opening file : IOSTAT = 29 file not found, unit 3, file E:\ProgramData\test\abc ! 返回错误信息,说明该文件abc不存在
4) 文件定位
Fortran提供两条语句,帮助在顺序文件内容来回移动:
-
BACKSPACE
,每次调用都会回退一条记录; -
REWIND
,倒回文件,可以从文件首部重新开始,可用于倒回临时文件,如下例所示:PROGRAM scratch_file IMPLICIT NONE INTEGER,PARAMETER::LU = 8 ! 临时文件I/O单元号 REAL:: data1 INTEGER::icount = 0 INTEGER::irecord INTEGER::j OPEN(UNIT = LU , STATUS = 'SCRATCH' ) ! 创建临时文件,状态为SCRATCH表示创建临时文件,此时不能指定具体文件名 WRITE(*,*) 'Enter positive or zero input values. A negative value terminates input.' readloop:DO ! 用于往临时文件中输入数据 WRITE(*,110) icount +1 110 FORMAT('Enter sample ',I4,' : ') READ(*,*) data1 IF(data1 < 0.) EXIT icount = icount + 1 WRITE(LU , 120) data1 ! 将数据以科学级数法形式写入临时文件中 120 FORMAT(ES16.6) END DO readloop WRITE(*,130) icount ! 提示可以读取临时文件中的数据,并显示范围 130 FORMAT('Which record do you want to see(1 to ',I4,' )? ') READ(*,*) irecord record_data:IF((irecord >= 1).AND.(irecord <= icount)) THEN ! 满足irecord的要求时 REWIND(UNIT = LU) ! 回倒临时文件 DO j = 1,irecord ! 对每一行数据进行遍历,直到结束,而结束时即为要查询的irecord(位置),然后输出相应数值 READ(LU,*) data1 END DO WRITE(*,140) irecord,data1 140 FORMAT('The value of record ' , I4 , ' is ' , ES12.5) ELSE record_data WRITE(*,150) irecord ! 如果不满足irecord要求,返回错误信息 150 FORMAT('Illegel record number entered:',I8) END IF record_data CLOSE(UNIT = LU) END PROGRAM scratch_file
相应结果为:
Enter positive or zero input values. A negative value terminates input. Enter sample 1 : 12.0 ! 键盘输入,以下同理 Enter sample 2 : 23. Enter sample 3 : 66666 Enter sample 4 : 8884.2253 Enter sample 5 : 666.22 Enter sample 6 : -8 ! 输入结束 Which record do you want to see(1 to 5 )? ! 倒回输入的数据中寻找 4 The value of record 4 is 8.88423E+03