今天聊一聊Fortran中的输入和输出。作为科学计算语言,免不了涉及到数据的读取和输出(例如读取输入卡信息)。Fortran提供了十分简洁的输入输出函数,日常操作是完全够用了。

输出

Fortran中的输出函数有两个,分别是write和print。

1
2
1    write(*,*) "Hello World!"
2 print *, "Hello World!"

上述两个语句输出效果在这里是等价的,我们注意到write中有两个参数,这里都是星号*,这两个星号是默认参数,第一个参数是设置输出位置,默认为屏幕。第二个参数是设置输出格式,默认没有格式,完全输出。print输出到屏幕,唯一的参数是设置格式用的,不过不再推荐使用print函数,write已将print的功能覆盖。

这里先讲解一下Fortran的格式,常用的格式标识符如下(不区分大小写):

x 输出空格

a 输出字符串(不限字符个数)

i 输出整数(完整形式为iw.m)

f 浮点数(完整形式为fw.d)

e 指数形式(完整形式为ew.d)

上述w、d、m都是数字,w代表的是输出宽度,m代表要显示的最小位数,d是保留的小数位。在硬盘容量充足的情况下,不建议设置w、d、m参数,若是输出的数字小于设置的格式宽度,会输出一堆星号。另外相同的几个格式可以在格式前面加一个数字,例如输出n个空格,那么格式控制符就为nx。下面举个例子:

1
write(*,'(a,i5,2f6.2,a)') 'run', 5, 2.3, 2.3, "#"

输出结果为: run 5 2.30 2.30#

输入

1
read(*,*) a, b ,c

Fortran中的字符串双引号和单引号是等价的,前提是配对。能看到这里输出的位置是屏幕,write后面所跟输出变量以逗号隔开。老标准的格式控制符是通过format函数进行设置的,写法和这里类似。输入函数read默认是从屏幕中读取,read后面的变量会依次从屏幕中读取。输入数值空格隔开,回车结束输入。

文件操作

Fortran中打开文件都是通过open函数来完成的,例如我要打开一个名为test.txt的文件:

1
2
3
1    open(unit=10, file = 'test.txt')
2 rewind(10)
3 close(10)

open函数的第一个接收参量为文件标识符,可以类比C/C++中的文件指针。这里的unit=可以省略,第二个参量是文件名字,file=不可省略。这样就实现了一个文件的打开操作。rewind函数的功能是将文件指针返回到第一行,close函数用于关闭文件。下面举一个完整的例子:

先假设test.txt文件中有如内容:

1
2
3
1 2
3 4 5
6 7
1
2
3
4
5
6
7
8
9
10
11
12
1    program main
2 implicit none
3 integer :: a, b, c, d, e, f, g, h, k, m, n
4 open(10, file='test.txt')
5 read(10,*) a, b ! 1, 2
6 read(10,*) c, d ! 3, 4
7 read(10,*) e, f ! 6, 7
8 rewind(10)
9 read(10,*) g, h, k ! 1, 2, 3
10 read(10,*) m, n ! 6, 7
11 close(10)
12 end program main

Fortran默认可以识别文件中的数据分隔符为空格和逗号。每一个read函数结束后都会跳转到下一行,无论这行数据有没有读取完全(参考变量e、f、m、n的值),下一个read函数都会跳转到下一行数据。若只有一个read函数,没有接收变量,读取会跳过一行。读取数据时所当前行数据不够变量接收,则会自动续下一行,直到read函数后面变量都有接收值为止。最新标准还支持流读入输出(类似C++中的fstream),另外还有很多其他的flag,例如status可以检查文件状态,这里不再赘述。

注意

文件标识符最好都定义到10以上,因为10以下的标识符每种编译器可能会有默认值,例如在gfortran中标准输入(stdin)的标识符是5,标准输出(stdout)是6,标准错误输出(stderr)是0。

固定格式中函数语句是可以用数字起一个别名的,另外每一行头6个字符位是要预留的,都有不同的含义,若全是数字则就是别名,这里用format函数举一个例子。

要想实现和上面例子中同样的输出,我们重写为:

1
2
write(*,1000) 'run', 5, 2.3, 2.3, "#"
1000 format(a,i5,2f6.2,a)

其中1000是format的别名,在有很多输出函数格式一样的时候,用format设置会方便一些,因为只需要将格式定义一遍。format的这种标识方式在自由格式下也是可以使用的。