第8章 FORTRAN语言的文件操作
在前面介绍的程序中,结果都是输出在屏幕上,数据都是通过键盘送入内存单元,实际上数据的输入/输出也可在磁盘上。如图所示:
我们把放在磁盘上的数据称为数据文件。数据文件由
记录
混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载
组成,FORTRAN中对文件的存取以记录为单位,即:
输出时:一个输出语句的数据就是一个记录,叫写入文件。
输入时:一个输入语句需要的数据就是一个记录,叫读出文件。
本章讨论FORTRAN程序的文件操作,也就是FORTRAN程序对磁盘数据文件的操作——读/写方式,并描述数据文件的记录结构,以及在程序设计中怎样建立,使用这些数据的记录结构。
8.1文件的概念
8.1.1 文件的分类
1)按记录存储结构分:
顺序文件:文件记录存储按照时间顺序依次存放,记录的逻辑次序与物理顺序是一致的,不能随意读或取某个记录,必须从首记录开始访问。
直接文件:又叫随机文件,记录存放按记录号完成。
2)按记录数据存放格式分:
有格式文件:记录以字符形式(或称ASCII码形式)存储,文件的数据流由一个个的字符组成,每个字符占据一个字节,每条记录用回车和换行符作为结束符,可以用文本编辑器(如记事本)直接打开查看。
无格式文件:数据以计算机内部的二进制代码形式存放。如果用文本编辑器直接打开查看,只能看到乱码符号。
二进制文件:这是Microsoft的一种扩充模式,数据按其在内存中的存储形式存储在文件中,其数据流由二进制代码形式的一个个字节组成,结构最紧凑,适合保存大容量的数据。用文本编辑器直接打开查看也只能看到乱码。
归纳起来,FORTRAN语言的文件可以分为:
有格式(顺序文件、直接文件、二进制文件);
无格式(顺序文件、直接文件、二进制文件);
8.1.2 文件的操作
1)文件记录定位
文件在存取过程中,有一个文件指针控制着读写的位置,它总是指向当前进行输入或输出的那个记录,也可以通过语句拨动指针的位置。
2)文件操作的过程
打开文件:要求机器分配一个供该文件使用的I/O缓冲区。
读或写文件:将数据通过分配的I/O缓冲区向文件中读写记录。
关闭文件:告诉机器文件操作完成,取消缓冲区的使用权限。
8.2 文件相关操作语句
为了实现FORTRAN程序对文件的操作,FORTRAN 系统为用户提供了相应的文件操作语句,本节将详细讨论这些语句的语法及其用法。
8.2.1 OPEN语句
OPEN语句的功能就是打开一个文件,其语句的基本格式为:
OPEN(UNIT=unitspec, FILE=file, STATUS=status, ACCESS=access, BLANK=blanks,
FORM=form, MODE=mode, BLOCKSIZE=blocksize, RECL=recl, SHARE=share,
ERR=errlabel, IOSTAT=iocheck)
其中的大写部分是语句参数的标识名称,使用时照写(“UNIT=”可以省略);小写部分是语句参数的设定值,使用时根据需要设置。
如果忽略了UNIT= ,则unitspec必须是第一个参数。其它参数顺序可以任意。其中:
unitspec 指定一个文件缓冲区号,取值一般为2-255
file 字符表达式,通常指文件的名称。
statas 文件的状态,可以是:
‘OLD’—— 一个存在的文件(旧文件),如果文件存在,则打开。否则出现一个I/O错误。
‘NEW’—— 文件决不能存在。如果文件不存在,则创建该文件。否则出现一个I/O错误。
‘SCRATCH’—— 当打开一个文件时,若省略了fname参数,则statas的缺省值为‘SCRATCH’,它表示打开一个暂存文件。暂存文件是临时文件,当关闭或终止程序时文件将被删除。
‘UNKNOWN’—— 如果文件存在则打开,如果文件不存在则创建该文件。相当于‘OLD’与‘NEW’参数的综合应用。
access 文件存取方式。可以是:
‘APPEND’—— 附加方式(一般很少使用)。
‘DIRECT’—— 直接存取方式。
‘SEQUETIAL’—— 顺序存取方式。这是存取方式的默认值
blanks 对文件中的数据进行处理。
‘NULL’—— 忽略数据中的空格。
‘ZERO’—— 把数据中的空格处理为零。
form 文件操作时的数据格式。可以是:
‘FORMATTED’—— 有格式。
‘UNFORMATTED’—— 无格式。
‘BINARY’—— 二进码格式。
如果该项省略,对顺序文件是‘FORMATTED’,对直接文件是‘UNFORMATTED’。
mode 文件读/写属性。可以是:
‘READ’—— 文件只读。
‘WRITE’—— 文件只写。
‘READWRITE’——文件既可读也可写。
blocksize 整数表达式,用以指定文件缓冲区的大小。此项缺省时系统定义为1024字节。最大可以定义为32256字节。
recl 直接文件方式每条记录的长度,应该是整型表达式。
share 文件操作限制方式。应该字符表达式,可以是:
‘COMPAT’—— 兼容方式(DOS中的缺省方式)。当文件为文本方式时,原用户可以任意打开文件,其它用户则不能打开。
‘DENYRW’—— 禁止读/写方式。
‘DENYWR’—— 禁止写方式。
‘DENYRD’—— 禁止读方式。
‘DENYNONE’—— 非禁止方式。此方式文件可以任意操作。
errlabel 整型数,同一程序单元中可执行语句的标号,当文件操作发生一个I/O错误时,则转到指定标号去执行程序。
iocheck 整型变量,由此变量返回一个I/O状态值。如果未遇到错误,返回零。如果遇到一个文件尾记录,返回一个负值。如果遇到一个错误,则返回错误信息码。
OPEN语句的格式复杂,但在实际使用中很多参数都是可以省略的。
8.2.2 READ/WRITE语句
FORTRAN语言中对文件的操作仍然用READ和WRITE语句实现,但与前面各章的用法略有不同。
1)READ语句
功能:从指定文件中读取数据。
格式:
READ(u, f, END = endlabel, ERR=errlabel, REC=rec, IOSTAT=iocheck)变量名表
其中:
u —— 连接文件的逻辑设备号
f —— 某个FORMAT格式语句的标号
endlabel —— 遇到文件结束标记时转到本程序单元中可执行语句的标号。
errlabel —— 遇到一个读入错误时转到本程序单元中可执行语句的标号。
rec —— 为直接文件指定一个记录号。
iocheck —— 整型变量,用于返回读取操作的状态值。(见OPEN语句中的iocheck
参数说明)。
变量名表 —— 用于保存从文件中读取数据的变量序列。
例如: READ(9,*)A,B,C,D
从以9号文件缓冲区连接的顺序文件中以自由格式读取4个数据。分别存放到变量A、B、C、D中。
例如:READ(8,*,REC=5,ERR=150)(A(I),I=1,10)
在以8号文件缓冲区连接的直接文件中,从第5号记录内读取10个数据,分别赋给数组A中的诸元素。如果遇到一个读入错误,不中断程序执行,而转到标号为150的语句去继续执行程序。
2)WRITE语句
功能:把数据按一定的格式写入到指定的文件中去。
格式:WRITE(u, f, REC = rec, ERR=errlabel, IOSTAT= iocheck) 输出项目表
其中:
u —— 文件逻辑设备缓冲区号。
f —— 某个FORMAT格式语句的标号。
rec —— 指定直接文件的记录号。
errlabel —— 遇到一个写入错误时转到本程序单元中可执行语句的标号。
iocheck —— 整型变量,用于返回一个I/O状态值。见OPEN语句。
输出项目表 ——输出项目的列表,可以是数组、数组元素、变量、常量、表达式和函数。
例如:WRITE(8,*)A,B,C,D
把变量A、B、C、D中的数值按自由格式方式写入到与8号文件缓冲区相连的顺序文件中去。例如语句:WRITE(9,100,REC=6)(M(K),K=1,10)
100 FORMAT(10I6)
把数组M中的10个数据以100标号的FORMAT语句指定的格式写入到与9号文件缓冲区相连的直接文件第6号记录中去。
8.2.3 CLOSE语句
功能:于关闭一个指定的文件。
格式:CLOSE(u, ERR=errlabel, STATUS=status, IOSTAT=iocheck)
其中:
u —— 文件逻辑设备缓冲区号。
errlabel —— 遇到一个操作错误时转到本程序单元中可执行语句的标号。
status ——文件属性,可为一个字符表达式:
‘DEEP’为非常文件。一般为临时文件。
‘DELETE’关闭时删除的临文件。
iocheck ——整型变量,用以返回一个I/O状态值,见OPEN语句。
例如语句:CLOSE(9),表示关闭与9号文件缓冲区相连的文件。
关闭文件指切断文件与文件缓冲区的连接,禁止对文件进行读/写操作。一般情况下,当程序停止执行时,系统将自动关闭所有打开的文件。在程序设计中,为不引起文件操作的混乱,正常情况下,对一个已打开的文件,如果不再对其操作,一般应将其关闭。
8.2.4 REWIND语句
在FORTRAN文件操作中,顺序文件是按数据顺序操作的,直接文件虽然可以指定记录号,但在每条记录中的数据还是按顺序的。如果要对文件前面、中间或最后的数据进行操作,则需要一些特殊的语句来完成。
功能:将文件的指针重新定位在其第一条记录上。
格式:REWIND(u, ERR=errlabel, IOSTAT=iocheck)
其中:
u —— 文件逻辑设备号。
errlabel —— 遇到一个I/O错误,转到本程序单元中可执行语句的标号。
iocheck ——整型变量,返回I/O操作状态值,见OPEN语句。
例如有一个数据文件A.DAT的数据如下:
1,2,3
4,5,6
7,8,9
有程序如下:
OPEN(8,FILE=’A.DAT’)
READ(8,*)A,B,C
READ(8,*)X,Y
REWIND(8)
READ(8,*)A1,B1,C1
CLOSE(8)
WRITE(*,*)A,B,C
WRITE(*,*)X、Y’
WRITE(*,*)A1,B1,C1
END
程序运行后的结果显示:
1.000000 2.000000 3.000000
4.000000 5.00000
1.000000 2.00000 3.000000
从显示结果中可以看出,当读入数据到变量Y时,文件指针指向数据6。执行REWIND语句后,文件指针指向数据1,然后重读A1,B1,C1。它们的数据分别为1,2,3。
8.2.5 BACKSPACE语句
功能:从当前记录位置回退到上一个记录位置。
格式:BACKSPACE(u, ERR=errlabel, IOSTAT=iocheck)
其中:
u ——文件逻辑设备号。
errlabel ——遇到一个I/O错误时转到本程序单元中可执行语句的标号。
iocheck ——整型变量,返回I/O操作状态值。见OPEN语句。
例如有数据文件A.DAT:
1,2,3
4,5,6
7,8,9
执行程序:
OPEN(8,FILE=’A.DAT’)
READ(8,*)I,J,K
READ(8,*)M,N
BACKSPACE(8)
READ(8,*)I1,J1,K1
CLOSE(8)
WRITE(*,*)I,J,K
WRITE(*,*)M,N
WRITE(*,*)I1,J1,K1
END
程序执行后显示:
1 2 3
4 5
4 5 6
8.2.6 ENDFILE语句
功能:把一个记录作为文件末尾记录写入文件中。原文件末尾记录被写入记录更新。
格式:ENDFILE(u,ERR=errlabel,IOSTAT=iocheck)
其中: u —— 文件逻辑设备号。
errlabel ——遇到一个I/O错误转到本程序单元中的可执行语句标号。
iocheck ——整型变量,用于返回I/O状态值,见OPEN语句。
要特别注意的是,如果打开文件时,文件指针指向第一个记录位置。这时使用ENDFILLE语句后,写入的记录作为文件尾记录,原文件记录将被全部删除。这是要特别注意的地方。
例如有数据文件A.DAT数据如下:
1,2,3
4,5,6
7,8,9
10
执行程序:
DIMENSION M(10)
OPEN(8,FILE=’A.DAT’)
READ(8,*)(M(I),I=1,10)
WRITE(*,’(5X,3I5)’)(M(I),I=1,10)
BACKSPACE(8)
WRITE(8,’(I2)’)11
ENDFILE(8)
REWIND(8)
CLOSE(8)
END
程序运行后显示:
1 2 3
4 5 6
7 8 9
10
但是原数据文件A.DAT已经改变,它的文件末尾记录被写入数据11。其文件A.DAT现在数据如下:
E:\ FOR>TYPE A.DAT
1,2,3
4,5,6
7,8,9
11
8.2.7 INQUIRE语句
功能:返回一个设备或文件的各种特性。
格式:INQUIRE([UNIT=]unitspec∣FILE=file[,ACCESS=access][,BINARY=binary]
[,BLANK=blank][,BLOCKSIZE=blochsize][,DIRECT=direct][,ERR=errlabel]
[,EXIST=exist][,FORM=form][,FORMATTED=formatted][,IOSTAT=iocheck]
[,MODE=mode][,NAME=name][,NAMED=named][,NEXTREC=nextrec][,NUMBER=num]
[,OPENED=opened][,RECL=recl][,SEQUENTIAL=seq][,SHARE=share]
[,NUFORMATTED=unformatted])
其中,“|”表示[UNIT=]unitspec和FILE=file两项只能选择一项。各参数含义为:
unitspec 逻辑设备号或文件缓冲区号。
file 字符表达式,外部文件的名称。
access 字符变量,返回‘SEQUENTIAL’(顺序方式),或返回‘DIRECT’(直接方式)。
binary 字符变量,如果文件为二进码格式,返回‘YES’,否则返回‘NO’或‘UNKNOWN’。
blank 字符变量,如果文件数据忽略空格返回‘NULL’,如果空处理为零,则返回‘ZERO’。
blocksize 整型变量,返回文件缓冲区大小的字节数。
direct 字符变量,如果文件是直接方式,返回‘YES’,否则返回‘NO’或‘UNKNOWN’。
errlabel 同一程序单元中可执行语句的标号。
exist 逻辑变量,如果文件存在返回.TRUE.,否则返回.FALSE.。
form 字符变量,如果文件是有格式的,返回‘FORMATTED’。
formatted 字符变量,如果文件是带格式文件,返回‘YES’,否则返回‘NO’或‘UNKNOWN’。
iocheck 整型变量,返回I/O操作的状态值。
mode 字符变量,返回文件的模式状态。与OPEN语句说明的模式一样,即为‘READ’、‘WRITE’和‘READWRITE’。
name 字符变量,返回与缓冲区相连的文件名。
named 逻辑变量,如果文件没有打开或文件是一个临时文件,返回.FALSE.,否则返回.TRUE.。
nextrec 整型变量,返回直接文件中的下一个记录号。
num 整型变量,返回与文件相连的文件缓冲区号。
opened 逻辑变量,如果文件与设备相连,返回.TRUE.,否则返回.FALSE.。
recl 整型变量,返回直接文件方式的记录长度。
seq 字符变量,文件为顺序模式,返回‘YES’,否则返回‘NO’或‘UNKNOWN’。
share 字符变量,返回指定文件的当前共享状态,与OPEN语句说明的一样为:‘COMPT’、‘DENYRW’,‘DENYWR’、‘DENYRD’和‘DENYNONE’。
unformatted 字符变量,若文件为无格式方式,返回‘YES’,否则返回‘NO’或‘UNKNOWN’。
当用户对未知文件或虽然是用户自己的文件,但时间长现在记不清楚的时候,INQUIRE语句可以帮助用户返回文件的相关特性信息。例如现在有一批文件名准备要对其进行操作,但不知磁盘上是否有这些文件。那么下面的程序可以获得文件是否存在的信息。程序如下:
CHARACTER fm*15
LOGICAL ex
77 WRITE(*,‘(A)’)‘Enter the file name:’
READ(*,‘(A)’)fm
INQUIRE(FILE=fm, EXIST=ex)
IF(.NOT.ex)THEN
WRITE(*,‘(10x,A,1X,A)’)‘Cannot find file’,fm
GOTO 77
ENDIF
END
程序运行显示如下:
Enter the file name:
S.DAT
Cannot find file S.DAT
Enter the file name:
S1.DAT
Cannot find file S1.DAT
Enter the file name:
A.DAT
E:\ FOR>
程序运行提示输入文件名并回车,如果文件存在,则停止执行程序。若文件不存在,则继续查找。
使用INQUIRE语句可根据要查询的项目选择相关参数,通常情况下很少会用到全部参数项。除UNIT项或FILE项必须放在第一项的位置外,其余参数项的位置可以任意。
8.3 文件的使用
FORTRAN程序中对于文件的使用是程序设计的基础技能之一。文件的使用可以避免从键盘输入数据容易出错的问题,数据文件的保存可以保留大量有用的数据及重复使用这些数据,并可以相互利用这些数据。特别是不同语言程序之间的磁盘数据共享,使用文件是非常实用的手段。
按照文件分类,本节将依次介绍:
有格式顺序文件的使用;无格式顺序文件的使用。
有格式直接文件的使用;无格式直接文件的使用。
有格式二进制文件的使用;无格式二进制文件的使用。
8.3.1 有格式顺序文件的使用
【例8.1】 把20个整型数和20个实型数以有格式顺序方式存入文件SF1.DAT中。
程序如下:
DIMENSION M(20),A(20)
DO 10 I=1,20
M(I)=I**2
A(I)=SIN(I*1.2)
10 CONTINUE
OPEN(8,FILE='D:\SF1.DAT',STATUS='UNKNOWN')
WRITE(8,'(5I5)') (M(I),I=1,20)
WRITE(8,'(5F10.6)') (A(I),I=1,20)
CLOSE(8)
END
程序运行之后,没有任何显结果。用记事本将D:\SF1.DAT文件打开可看见结果:
从建立的SF1.DAT文件可以看出有格式顺序文件的基本数据模式。文件建好之后,可以用另一个FORTRAN程序读取这些数据。
【例8.2】 编写一程序,把文件SF1.DAT中的数据读出,并分别求20个整型数与20个实型数的和。
DIMENSION M(20),A(20)
OPEN(8,FILE='SF1.DAT')
READ(8,*) (M(I),I=1,20)
READ(8,*) (A(I),I=1,20)
CLOSE(8)
DO 10 I=1,20
N=N+M(I)
S=S+A(I)
10 CONTINUE
WRITE(*,'(2X,I7,5X,F16.7)') N,S
END
程序运行后显示:
2870 -.0319510
以上两个例子可以看出,如果要使程序建立的数据文件具有显示与再编辑功能,可以使用有格式顺序文件。
8.3.2 无格式顺序文件的使用
【例8.3】 编写一程序,产生30个随机整数,把这30个随机整数以无格式顺序文件方式存入文件SF2.DAT中。
DIMENSION M(30)
DO 10 I=1,30
M(I)=RAND()*100
10 CONTINUE
OPEN(9,FILE='D:\SF2.DAT',STATUS='UNKNOWN',FORM='UNFORMATTED')
WRITE(9) (M(I),I=1,30)
CLOSE(9)
END
FUNCTION RAND()
SAVE SEED
INTEGER SEED,C1,C2,C3
PARAMETER (C1=29,C2=217,C3=1024)
DATA SEED/12/
SEED=MOD(SEED*C1+C2,C3)
RAND=REAL(SEED)/C3
RETURN
END
程序运行后磁盘上有一个SF2.DAT文件。用记事本打开可看见结果:
以上显示的SF2.DAT文件的内容,只是一系列ASCⅡ码,具体数据是不清楚的,这是无格式文件的特点。但这些数据并非不能使用,可以用无格式文件方式来读取它。
【例8.4】 编写一程序,读取文件SF2.DAT中的数据,并把这些数据按从大到小的顺序排列。
DIMENSION M(30)
OPEN(9,FILE='D:\SF2.DAT',FORM='UNFORMATTED')
READ(9) (M(I),I=1,30)
CLOSE(9)
CALL PX(M,30)
WRITE(*,'(2X,10I6)') (M(I),I=1,30)
END
SUBROUTINE PX(M,N)
DIMENSION M(N)
DO 10 I=1,N
DO 20 J=I,N
IF(M(J).GT.M(I)) THEN
K=M(I)
M(I)=M(J)
M(J)=K
END IF
20 CONTINUE
10 CONTINUE
RETURN
END
程序运行后显示:
99 94 90 89 76 75 74 71 67 66
65 61 55 53 51 50 49 48 44 39
38 32 29 25 24 22 21 18 15 6
以上程序可以看出,无格式顺序文件虽然以二进制形式存盘,但读取这些数据还是很方便的。
8.3.3 有格式直接文件的使用
【例8.5】 已知有五个学生的姓名及每个学生的5科成绩。编写一程序,把每个学生的姓名及5科成绩以有格式直接文件的方式存入文件SF3.DAT。
DIMENSION M(5,5)
CHARACTER NAME(5)*8
DATA NAME/'李 鸣','汪小莉','罗 乾','王小刚','蒋 涵'/
DATA M/98,89,67,77,56,
$ 60,66,75,70,87,
$ 91,85,78,88,68,
$ 92,67,73,80,77,
$ 90,92,89,94,86/
OPEN(10,FILE='D:\SF3.DAT',STATUS='UNKNOWN',ACCESS=
$ 'DIRECT',RECL=35,FORM='FORMATTED')
DO 10 I=1,5
WRITE(10,'(A10,5I5)',REC=I) NAME(I),M(I,1),M(I,2),
& M(I,3),M(I,4),M(I,5)
10 CONTINUE
END
程序运行后,磁盘上建立了一个SF3.DAT文件,其内容如下:
李 鸣 98 60 91 92 90
汪小莉 89 66 85 67 92
罗 乾 67 75 78 73 89
王小刚 77 70 88 80 94
蒋 涵 56 87 68 77 86
程序中,把每个学生的数据(姓名,5科成绩)作为一个子纪录写入文件SF3.DAT。在程序的写入语句中,既要有数据格式描述,也要指定子记录号,这是读者应当注意的地方。
由于直接文件可以对其子记录数据任意操作,因此,对建好的文件可以随机读取它的子记录数据。这是直接文件的特点。
【例8.6】 编写一程序,以随机查询方式读取文件SF3.DAT中的子记录数据。
DIMENSION M(5)
CHARACTER NAME*8
OPEN(11,FILE='D:\SF3.DAT',ACCESS='DIRECT',
$ RECL=35,FORM='FORMATTED')
99 WRITE(*,*) ' Please input N=?'
READ(*,*) N
IF (N.EQ.0.OR.N.GT.5) STOP
READ(11,'(A10,5I5)',REC=N) NAME,(M(I),I=1,5)
WRITE(*,'(2X,A,2X,5I5)') NAME,(M(I),I=1,5)
GOTO 99
END
程序运行显示:
Please input N=? 5
蒋 涵 56 87 68 77 86
Please input N=? 2
汪小莉 89 66 85 67 92
Please input N=? 1
李 鸣 98 60 91 92 90
Please input N=? 3
罗 乾 67 75 78 73 89
Please input N=? 4
王小刚 77 70 88 80 94
Please input N=? 0
Stop - Program terminated.
由程序运行可以看到,当随意指定一个子记录号,就把指定的学生姓名及5科成绩读出并显示出来。
8.3.4 无格式直接文件的使用
【例8.7】 编写一程序,产生5组随机小数,每组6个数,以无格式直接文件方式存入文件SF4.DAT中。
DIMENSION A(6)
OPEN(10,FILE='D:\SF4.DAT',STATUS='UNKNOWN',ACCESS=
$ 'DIRECT',RECL=50,FORM='UNFORMATTED')
DO 10 I=1,5
DO 20 J=1,6
A(J)=RAND()
20 CONTINUE
WRITE(10,REC=I) (A(J),J=1,6)
10 CONTINUE
END
FUNCTION RAND()
SAVE SEED
INTEGER SEED,C1,C2,C3
PARAMETER (C1=29,C2=217,C3=1024)
DATA SEED/12/
SEED=MOD(SEED*C1+C2,C3)
RAND=REAL(SEED)/C3
RETURN
END
程序运行后磁盘上有SF4.DAT文件。是一个非文本格式文件。
【例8.8】 编写一程序,任意读取SF4.DAT中的子记录数据并显示。
DIMENSION B(6)
OPEN(11,FILE='D:\SF4.DAT',ACCESS='DIRECT',
$ RECL=50,FORM='UNFORMATTED')
99 WRITE(*,*) ' Please input N=?'
READ(*,*) N
IF (N.EQ.0.OR.N.GT.5) STOP
READ(11,REC=N) (B(I),I=1,6)
WRITE(*,'(2X,6F10.6)')(B(I),I=1,6)
GOTO 99
END
程序运行显示:
Please input N=? 1
.551758 .212891 .385742 .398438 .766602 .443359
Please input N=? 5
.153320 .658203 .299805 .906250 .493164 .513672
Please input N=? 3
.258789 .716797 .999023 .183594 .536133 .759766
Please input N=? 4
.245117 .320313 .500977 .740234 .678711 .894531
Please input N=? 2
.069336 .222656 .668945 .611328 .940430 .484375
Please input N=? 0
Stop - Program terminated.
由程序结果可以看出,无格式直接文件对其子记录数据的任意读取也是非常方便的。
8.3.5 二进制顺序文件的使用
【例8.9】 编写一程序,产生300个随机整数,并把这300个随机整数以二进制顺序文件方式存入文件SF5.DAT中。
DIMENSION N(300)
DO 10 I=1,300
N(I)=RAND()*100
10 CONTINUE
OPEN(9,FILE='D:\SF5.DAT',STATUS='UNKNOWN',FORM='BINARY')
WRITE(9) (N(I),I=1,300)
CLOSE(9)
END
FUNCTION RAND()
SAVE SEED
INTEGER SEED,C1,C2,C3
PARAMETER (C1=29,C2=217,C3=1024)
DATA SEED/12/
SEED=MOD(SEED*C1+C2,C3)
RAND=REAL(SEED)/C3
RETURN
END
程序运行之后,在磁盘上建立了一个SF5.DAT文件,存入300个数,文件占用1200字节。而文件SF1.DAT存入40个数,占用316字节。由此可以看出,二进码文件可以节省文件空间。
【例8.10】 编写一程序,读取二进码顺序文件SF5.DAT的300个数据,求这些数据之和与平均值。
DIMENSION M(300)
OPEN(9,FILE='D:\SF5.DAT',FORM='BINARY')
READ(9) (M(I),I=1,300)
CLOSE(9)
WRITE(*,'(2X,10I5)') (M(I),I=1,300)
DO 10 I=1,300
N=N+M(I)
10 CONTINUE
S=N/300.
WRITE(*,*) 'N=',N
WRITE(*,*) 'S=',S
END
运行后显示:
55 21 38 39 76 44 6 22 66 61
94 48 25 71 99 18 53 75 24 32
50 74 67 89 15 65 29 90 49 51
10 35 52 30 10 24 23 3 28 56
63 70 65 32 72 31 21 52 50 85
96 16 96 33 89 23 12 75 1 75
96 10 32 69 48 40 82 8 70 63
50 91 60 79 37 17 19 90 43 87
47 94 68 0 43 92 11 58 9 84
73 59 43 70 54 4 45 49 54 92
17 22 72 25 57 89 9 1 66 49
65 21 44 4 40 85 90 52 33 92
5 93 45 43 89 29 76 38 42 58
26 77 64 81 94 59 54 98 81 85
13 9 87 55 41 13 12 69 37 11
55 26 2 3 17 28 36 88 98 73
39 68 97 61 11 41 16 94 51 8
53 70 60 68 9 90 37 22 83 53
84 70 77 61 99 12 89 12 83 48
20 7 36 77 69 46 57 0 38 28
48 17 25 54 7 27 31 24 34 32
55 38 31 30 99 95 96 22 61 96
30 7 42 41 33 86 41 30 4 59
60 62 45 26 97 39 54 87 53 58
31 41 27 22 78 89 20 30 93 31
33 81 77 66 63 76 30 96 13 14
51 19 81 97 41 36 69 23 0 46
74 93 28 50 99 7 25 49 42 64
90 40 4 65 24 26 85 10 27 5
85 99 98 78 3 31 38 45 40 7
N= 14782
S= 49.273330
8.3.6 二进制直接文件的使用
与无格式直接文件一样,为了节省文件空间,可以把直接文件中的子记录数据以压缩二进码格式存盘。以下例子可以说明它的使用方法。
【例8.11】 编写一程序,以二进码直接文件方式向文件SF6.DAT中写入15个子记录,每个子记录6个实型数,这些数据都是正弦函数值。
DIMENSION A(6)
OPEN(10,FILE='SF6.DAT',STATUS='UNKNOWN',ACCESS=
$ 'DIRECT',RECL=50,FORM='BINARY')
DO 10 I=1,15
DO 20 J=1,6
A(J)=SIN(3.14159*J/(I*2))
20 CONTINUE
WRITE(10,REC=I) (A(J),J=1,6)
10 CONTINUE
END
程序运行之后,在盘上建立一个SF6.DAT二进码直接文件。90个实型数(6位小数)只占用750个字节。
【例8.12】 编写一程序以随机查询方式,读取二进码直接文件SF6.DAT中的任意子记录数据,并打印显示这些数据。
DIMENSION A(6)
OPEN(10,FILE='SF6.DAT',ACCESS=
$ 'DIRECT',RECL=50,FORM='BINARY')
97 WRITE(*,*) 'Please input N=?'
READ(*,*) N
IF (N.EQ.0.OR.N.GT.15) STOP
READ(10,REC=N) (A(I),I=1,6)
WRITE(*,'(2X,6F10.6)')(A(J),J=1,6)
GOTO 97
END
程序运行显示:
Please input N=? 1
1.000000 .000003 -1.000000 -.000005 1.000000 .000008
Please input N=? 10
.156434 .309017 .453990 .587785 .707106 .809017
Please input N=? 15
.104528 .207912 .309017 .406736 .500000 .587785
Please input N=? 8
.195090 .382683 .555570 .707106 .831469 .923879
Please input N=? 9
.173648 .342020 .500000 .642787 .766044 .866025
Please input N=? 3
.500000 .866025 1.000000 .866026 .500002 .000003
Please input N=? 0
Stop - Program terminated.
8.3.7文本文件的使用
文本文件是在WINDOWS下用任何文本编辑程序建立的数据文件。当然,磁盘上任一个带格式可显示的数据文件(也可以是其它高级语言程序写入的文件)都可以作为文本文件来使用。
FORTRAN中使用文本数据文件的方式是带格式的方式,关键在于怎样去读取这些记录。
例如,D盘根目录下有数据文件B.DAT,内容如下:
1,2,3,4,5
6,7,8,9,10
11,12,13,14,15
16,17,18,19,20
【例8.13】 编写一程序,读取并显示文件B.DAT中的数据。
OPEN(7,FILE='D:\B.DAT')
DO 10 I=1,4
READ(7,*) N1,N2,N3,N4,N5
WRITE(*,100) N1,N2,N3,N4,N5
10 CONTINUE
100 FORMAT(5X,5I5)
END
程序运行后显示:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
【例8.14】 编写一程序,读取显示文件B.DAT中的数据。
OPEN(7,FILE='D:\B.DAT')
DO 10 I=1,20
READ(7,*,END=100) N
WRITE(*,*) N
10 CONTINUE
100 STOP
END
程序运行后显示:
1
6
11
16
Stop-Program terminated
程序采用在循环中一次读一个数据,读20次。从表面看,程序没有问题,但B.DAT文件中只有4个记录,一个记录5个数。用这种方式读取实际上只读取4次,就遇到了文件末尾的数据结束标志。马上转到100标号去执行,停止程序运行。因此只读到文件中的4个数据。这是需要读者注意的地方。
【例8.15】 编写一程序,读取文件B.DAT中的数据,并把这些数据求和。
DIMENSION M(20)
OPEN(6,FILE='D:\B.DAT')
READ(6,*) M
WRITE(*,100) (M(I),I=1,20)
100 FORMAT(5X,5I5)
DO 10 I=1,20
S=S+M(I)
10 CONTINUE
WRITE(*,*) 'S=',S
END
程序运行显示如下:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
S= 210.000000
程序采用了数组整体读取数据。如果需要读取文件中的全部数据这是一种较好的方法之一。文本数据文件中的数据,有的需要把连续几个相同的数据简写为N*X方式。FORTRAN程序仍然可以正确读取这些数据。
例如,有文件S3.DAT的内容如下:
1,2,3,4,5,6,7,8,9,10
5*20,5*30,5*40,5*50
【例8.16】 编写一程序,读取文件S3.DAT中的全部数据,并求它们的平均值。
DIMENSION M(30)
OPEN(7,FILE='S3.DAT')
READ(7,*) (M(K),K=1,30)
WRITE(*,100) (M(I),I=1,30)
100 FORMAT(5X,10I5)
DO 10 I=1,30
S=S+M(I)
10 CONTINUE
T=S/30
WRITE(*,*) 'S=',S
WRITE(*,*) 'T=',T
END
程序运行显示如下:
1 2 3 4 5 6 7 8 9 10
20 20 20 20 20 30 30 30 30 30
40 40 40 40 40 50 50 50 50 50
S= 755.000000
T= 25.166670
程序采用了隐含循环方式读取文件中的数据,这种方法可以不管文件中的数据记录结构形式,都可以正确地读取数据。在FORTRAN程序对文本文件使用的4种读数方式中,使用数组隐含循环方式读取数据相对比较优越,因此,建议文件读数采用这种方法。
本章讨论了FORTRAN语言文件的具体用法,它们的数据记录结构可以是文本方式,有格式顺序方式,无格式顺序方式,有格式直接方式,无格式直接方式,二进码顺序方式和二进码直接方式等。值得说明的是,如果是其他计算机高级语言程序建立的数据文件,只要符合FORTRAN文件的记录结构,FORTRAN程序都可以很方便地读取这些数据,这为混合编程和磁盘数据文件共享提供了有力的保证。
习 题 8
8.1 利用随机数子程序产生100个随机整数,把这些数按从大到小的顺序排列之后,以有格式顺序文件方式存盘。
8.2 已知函数y=1.5sinx, 当x=0.1,0.2,0.3……10时计算这些函数值,并把这些值以无格式顺序文件方式存盘。
8.3 已知一组数据如下:
王 明:90, 85, 70, 60, 65, 91
李 军:91, 80, 81, 75, 77, 82
李小诗:60, 72, 91, 92, 80, 93
朱 峰:60, 89, 79, 80, 92, 85
李小林:91, 80, 75, 89, 80, 75
石 磊:75, 73, 69, 81, 78, 90
孙 梅:78, 92, 81, 83, 79, 87
王轶军:60, 70, 75, 85, 93, 85
刘海涛:89, 79, 83, 91, 92, 95
刘学海:90, 91, 78, 85, 89, 96
此数据为10个学生的姓名及6科课程的考试成绩。编写一程序,以有格式直接文件方式把这些数据存入文件ex3.dat,要求一个学生的数据资料建一个子记录。
8.4 编写一程序,用随机查询方式读取8.5题中ex3.dat文件的数据,并把这些数据以姓名、高等数学、结构力学、物理、化学、计算机文化基础、制图课程的表格格式输出。
8.5 编写一程序,每一弧度计算一个y=cosx的值,计算到360弧度。并把这些计算结果以二进码顺序文件方式存盘。
8.6 编写程序并调试运行
(1) 编程序计算20,21,22,……213,并把这些数据以有格式顺序文件方式存盘,文件名为FEX1.DAT。运行结束后,打开数据文件查看内容是否正确。
(2) 用编辑工具建一个文本数据文件A.DAT:
5*10,5*20,5*30,5*40,5*50
5*1, 5*2, 5*3, 5*4, 5*5
再编写一程序,读取文件A.DAT中的全部数据,并把这些数据放入两个5阶方阵。求两个矩阵之和。
(3) 编写一程序,利用随机数子程序产生10组数,每组5个实型数,并把这些数以有格式直接文件方式存盘,每组数为一个子记录。
8.7 已知一文本数据文件ex1.dat存有200个整数,编写一程序,读取这200个整数,并求其平均值。
8.8 已知一文本数据文件ex2.dat存有100个实型数,编写一程序,读取这些数放入一个数组,并把这些数按从小到大的顺序排列。
实验十三 数据文件及应用
一、实验要求:
1.理解数据文件的概念
2.掌握使用文件的方法及程序设计
3.学会查看数据文件
二、实验步骤
1. 打开 Microsoft Developer Studio,建立项目,调试下面程序,理解使用文件的方法
PROGRAM MAIN
PARAMETER (N=5)
INTEGER SUM,M(N)
OPEN(1,FILE=‘D:\A.DAT’,STATUS=’NEW’)
SUM=0
DO K=1,N
M(K)=K
SUM=SUM+M(K)
END DO
WRITE(1,100)(M(L),L=1,N)
WRITE(1,*)’SUM=’,SUM