《FORTRAN SYNTAX》第7章 输入&输出

(7.1) 格式化WRITE语句

表控输出(List-directed input):输出语句的输出列表中的类型决定输出数据的格式。

WRITE(*,*) "Hello,Fortran!"
!WRITE(unit=*,fmt=*) "Hello,Fortran!"
PRINT*,"Hello,Fortran!"

(1)第一个星号代表默认设备即屏幕;第二个星号代表不设置输出格式。
(2)PRINTWRITE的区别是PRINT没有设置输出位置的能力,只能针对屏幕输出。
(3)WRITE语句执行后会自动换行。

这里不讨论输出设备。在设置格式时有以下三种风格:

!第一种写法
WRITE(*,"('a = ',I3)") a
!第二种写法
WRITE(*,100) a
100 FORMAT("a = ",I3)
!第三种写法
CHARACTER(10) :: str = "('a = ',I3)"
WRITE(*,str) a

整型输出:[n]Iw[.m](输出n个整型数,每个整型数占w个字符宽度,其中纯数字部分占m个字符宽度)

WRITE(*,"(I5)") -12 !□□-12
WRITE(*,"(I5.3)") -12 !□-012
WRITE(*,"(I3)") 1000 !***
WRITE(*,"(I0)") -12 !-12

实型输出:[n]Fw.d(输出n个实型数,每个实型数占w个字符宽度,其中小数部分占d个字符宽度)

WRITE(*,"(F9.3)") 123.45 !□□123.450

非标准科学计数法输出:[n]Ew.d[Ee](以非标准科学计数法的方式输出n个实型数,每个实型数占w个字符宽度,尾数在0.1~1.0之间,尾数的小数部分占d个字符宽度,指数部分占e个字符宽,一般要求w ≥ \ge d+7)

WRITE(*,"(ES15.7)") 123.45 !□□1.2345000E+02
WRITE(*,"(ES9.2E3)") 12.34 !1.23E+001

标准科学计数法输出:[n]ESw.d[Ee](以标准科学计数法的方式输出n个实型数,每个实型数占w个字符宽度,尾数在1.0~10.0之间,尾数的小数部分占d个字符宽度,指数部分占e个字符宽,一般要求w ≥ \ge d+7)

WRITE(*,"(E15.7)") 123.45 !□□0.1234500E+03
WRITE(*,"(E9.2E3)") 12.34 !0.12E+002

逻辑型输出:[n]Lw(输出n个逻辑型数据,每个逻辑型数据占w个字符宽度)

WRITE(*,"(L3)") .TRUE. !□□T

字符(串)型输出:[n]A[w](输出n个字符(串)型数据,每个字符(串)型数据占w个字符宽度)

WRITE(*,"(A6)") "Hello" !□Hello
WRITE(*,"(A3)") "Hello" !Hel
WRITE(*,"(A)") "Hello" !Hello
WRITE(*,"(2A6)") "Hello","World" !□Hello□World

左右移动位置输出:nX、TRn、TLn

WRITE(*,"(2X,I3)") 100 !先向右移动2个单位,再输出100,即:□□100
WRITE(*,"(TR2,I3)") 100 !先向右移动2个单位,再输出100,即:□□100
WRITE(*,"(A10,TL3,I3)") "Call 119",110 !□□Call□110

跳跃至特定列输出:Tc

WRITE(*,"(T3,I3)") 100 !□□100

换行输出:/

WRITE(*,"(I3/I3)") 10,10
WRITE(*,"(I3,/,I3)") 10,10 !两种写法等价

下面介绍几种重复使用某一个或某一组格式的方法:

100 FORMAT(I2,2(I3,F3.1)) !100 FORMAT(I2,I3,F3.1,I3,F3.1)
100 FORMAT(I2,*(I3,F3.1)) !无限使用(I3,F3.1)描述符,直到没有可输出的数据为止

(7.2) 格式化READ语句

表控输入(List-directed input):变量列表中的变量类型决定输入数据需要的格式。

INTEGER :: i
READ(*,*) i
!READ(unit=*,fmt=*) i

(1)若要同时输入多个数据,可以用逗号空格回车将数据分开。
(2)第一个星号代表默认设备即键盘;第二个星号代表不设置输入格式。
(3)在读入字符串时,如果字符串中含有空格或逗号,则需要将字符串用单/双引号括起来。
(4)如果读取的字符串超出设定范围,多余部分被舍去;小于设定范围,多余部分以空格填充。
(5)在读取含有逗号或空格的字符串如Hello,□world时,必须将读取格式设置为A12

这里不讨论输入设备。在设置格式时有以下三种风格,这三种写法的意思均为指定跳过输入缓冲区的前6列,然后第7~12列的内容将被解释为整数,并将输入的数据保存到整型变量a中。

!第一种写法
READ(*,"(6X,I6)") a
!第二种写法
READ(*,100) a
100 FORMAT(6X,I6)
!第三种写法
CHARACTER(10) :: str = "(6X,I6)"
READ(*,str) a

(7.3) 文件操作

打开文件

OPEN(KEYWORD = xxx,...)
  1. UNIT:设置文件代码,可以是常量或变量,但应该避开键盘的位置(1、5)和屏幕的位置(2、6)。
  2. FILE:设置所要操作文件的名称,Windows不区分大小写,Unix区分大小写。
  3. FORM:设置文件的保存格式。‘formated’(默认)表示文件使用“文本文件”格式保存;'unformatted’表示文件使用“二进制”格式保存。
  4. STATUS:设置文件状态。'new’表示文件不存在;'old’表示文件原本就已经存在;'replace’表示若文件存在重新创建,若不存在就新建;'scratch’表示打开暂存盘,程序结束后就自动删除;‘unknown’(默认)通常和’replace’一样。
  5. ACCESS:设置读取文件的方法。‘sequential’(默认)表示顺序读取;'direct’表示直接读取。
  6. RECL:设置一次可以读写多大容量的数据(顺序读取);设置文件中每一个模块单元的分区长度(直接读取)。
  7. ERR:设置当文件打开发生错误时,程序跳跃到行代码xxx处继续执行程序。
  8. IOSTAT:获取文件的打开状态。文件终了xxx<0;读取正常xxx=0;读取发生错误xxx>0。
  9. BLANK:设置字段中空格所代表的意义。 'null’表示空格代表没有东西;'zero’表示空格代表0。
  10. POSITION:设置文件打开时的读写位置。 'asis’表示文件打开时的读取位置,通常是文件的开头;'rewind’表示文件打开时的读取位置移动到文件开头;'append’表示文件打开时的读取位置移动到文件结尾。
  11. ACTION:设置待打开文件的读写权限。'read’表示只读;'write’表示只写;‘readwrite’(默认)表示读写。
  12. PAD:设置格式化输入时设置最前面的不足字段是否以空格填满。取值为’yes’(默认)、‘no’。
  13. DELIM:设置输出的字符串的显示风格。'none’表示纯粹输出字符串的内容;'quote’表示给输出字符串加上双引号;'apostrophe’表示给输出字符串加上单引号。

关闭文件

CLOSE(KEYWORD = xxx,...)
  1. UNIT:设置文件代码,可以是常量或变量,但应该避开键盘的位置(1、5)和屏幕的位置(2、6)。
  2. STATUS:设置文件关闭后文件的去留。‘keep’(默认)表示保留文件;'delete’表示删除文件。
  3. ERR:设置当文件关闭发生错误时,程序跳跃到行代码xxx处继续执行程序。
  4. IOSTAT:获取文件的关闭状态。文件终了xxx<0;关闭正常xxx=0;关闭发生错误xxx>0。

写数据

WRITE(KEYWORD = xxx,...)
  1. UNIT:设置文件代码,可以是常量或变量,但应该避开键盘的位置(1、5)和屏幕的位置(2、6)。
  2. FMT:设置写入格式。
  3. REC:设置所要写的文件的模块位置(直接读取)。
  4. ERR:设置当文件写入发生错误时,程序跳跃到行代码xxx处继续执行程序。
  5. IOSTAT:获取文件的写入状态。文件终了xxx<0;写入正常xxx=0;写入发生错误xxx>0。
  6. END:设置当写到文件末尾时,程序跳跃到行代码xxx处继续执行程序。
  7. NML:详细用法见namelist小节。
  8. ADVANCE:设置在文本格式下的顺序文件中,每一次写入后,写入位置是否自动换行,取值为’yes’、‘no’。
  9. SIZE:当ADVANCE='no’时,获取写入的字符数目。

读数据

READ(KEYWORD = xxx,...)
  1. UNIT:设置文件代码,可以是常量或变量,但应该避开键盘的位置(1、5)和屏幕的位置(2、6)。
  2. FMT:设置读取格式。
  3. REC:设置所要读取文件的模块位置(直接读取)。
  4. ERR:设置当文件读取发生错误时,程序跳跃到行代码xxx处继续执行程序。
  5. IOSTAT:获取文件的读取状态。文件终了xxx<0;读取正常xxx=0;读取发生错误xxx>0。
  6. END:设置当读到文件末尾时,程序跳跃到行代码xxx处继续执行程序。
  7. NML:详细用法见namelist小节。
  8. ADVANCE:设置在文本格式下的顺序文件中,每一次读取后,读取位置是否自动换行,取值为’yes’、‘no’。
  9. SIZE:当advance='no’时,获取读取的字符数目。

查询文件状态

INQUIRE(KEYWORD = xxx,...)
  1. UNIT:设置文件代码,可以是常量或变量,但应该避开键盘的位置(1、5)和屏幕的位置(2、6)。
  2. FILE:设置所要操作文件的名称,Windows不区分大小写,Unix区分大小写。
  3. IOSTAT:获取文件读取情况。文件终了xxx<0;读取正常xxx=0;读取发生错误xxx>0。
  4. ERR:设置当文件打开发生错误时,程序会跳跃到value所指的行代码处来继续执行程序。
  5. EXIST:检查文件是否存在,返回一个布尔变量给xxx,存在为.true.,反之为.false.。
  6. OPENED:检查文件是否已打开,返回一个布尔变量给xxx,已打开为.true.,反之为.false.。
  7. NUMBER:获取文件代码。
  8. NAMED:检查文件是否取了名字,也就是检查文件是否为临时保存盘。
  9. ACCESS:获取文件的读取方式,返回一个字符串。'sequential’表示文件是顺序读取;'direct’表示文件是直接读取;'undefined’表示没有定义。
  10. SEQUENTIAL:检查文件是否使用顺序读取,返回字符串’yes’、‘no’、‘unknown’。
  11. DIRECT:检查文件是否使用直接读取,返回字符串’yes’、‘no’、‘unknown’。
  12. FORM:获取文件保存方法,返回一个字符串。'formatted’表示文本文件;'unformatted’表示二进制文件;'unknown’表示没有定义。
  13. FORMATTED:检查文件是否为文本文件,返回字符串’yes’、‘no’、‘unknown’。
  14. UNFORMATTED:检查文件是否为二进制文件,返回字符串’yes’、‘no’、‘unknown’。
  15. RECL:获取打开文件时RECL栏的设定值。
  16. NEXTREC:获取下一次文件读写的位置。
  17. BLANK:获取打开文件时BLANK栏的设定值。
  18. POSITION:获取打开文件时POSITION栏的设定值。
  19. ACTION:获取打开文件时ACTION栏的设定值。
  20. READ:检查文件是否为只读文件,返回字符串’yes’、‘no’、‘unknown’。
  21. WRITE:检查文件是否为只写文件,返回字符串’yes’、‘no’、‘unknown’。
  22. READWRITE:检查文件是否为读写文件,返回字符串’yes’、‘no’、‘unknown’。
  23. DELIM:获取打开文件时DELIM栏的设定值。
  24. PAD:获取打开文件时PAD栏的设定值。

文件读写位置移动

BACKSPACE(UNIT = xxx,ERR = xxx,IOSTAT = xxx) !把文件的读写位置退回一步,其他字段参考前面
ENDFILE(UNIT = xxx,ERR = xxx,IOSTAT = xxx) !把目前文件的读写位置变成文件的结尾,其他字段参考前面
REWIND(UNIT = xxx,ERR = xxx,IOSTAT = xxx) !把文件的读写位置倒回文件开头,其他字段参考前面

顺序文件

顺序文件在读写时,不能任意跳跃到文件的某个位置读写数据,只能从头开始一步步向下进行。改变文件读写位置时,只能一步步地进退,或是直接移回文件开头或结尾。顺序文件的读取操作叫做顺序读取。来看两个写入文件、读取文件例子:

!学生成绩录入程序
PROGRAM main
    IMPLICIT NONE
    TYPE student
        CHARACTER(LEN = 10) :: name
        INTEGER :: chinese,math
    END TYPE student
    CHARACTER(LEN = 20) :: file_name = "e:\score.txt"
    INTEGER,PARAMETER :: file_id = 10
    INTEGER :: i,num,allocate_stat = 0
    TYPE(student),ALLOCATABLE :: students(:)
    WRITE(*,*) "请输入学生数量:"
    READ(*,*) num
    ALLOCATE(students(num),STAT = allocate_stat)
    IF(allocate_stat /= 0) THEN
        WRITE(*,*) "分配空间失败!"
        STOP
    END IF
    OPEN(UNIT = file_id,FILE = file_name,STATUS = 'replace')
    DO i = 1,num
        WRITE(*,"('请输入第',I3,'个学生的姓名:')") i
        READ(*,"(A8)") students(i)%name
        WRITE(*,*) "请输入语文、数学成绩:"
        READ(*,"(I3,I3)") students(i)%chinese,students(i)%math
        WRITE(UNIT = file_id,FMT = "(A8,I3,I3)") students(i)%name,students(i)%chinese,students(i)%math
    END DO
    CLOSE(UNIT = file_id)
END PROGRAM main
!显示目标文件内容程序
PROGRAM main
    IMPLICIT NONE
    INTEGER,PARAMETER :: file_id = 10
    CHARACTER(LEN = 79) :: file_name
    !这里之所以限制读取字符串的长度为79是因为在标准的DOS及Windows的cmd窗口下
    !一行只能显示80个字符,所以读太多字符在cmd窗口就显示不出来了,但是如果刚好输出80个字符
    !有的编译器所编译出来的程序会发生断行的现象,所以最好是79
    CHARACTER(LEN = 79) :: buffer !缓冲器,用来接收文件数据
    INTEGER :: read_stat = 0 !记录文件的读取状态
    LOGICAL :: is_exist !判断文件是否存在
    WRITE(*,*) "请输入文件名:"
    READ(*,"(A79)") file_name
    INQUIRE(FILE = file_name,EXIST = is_exist)
    IF(.NOT.is_exist) THEN
        WRITE(*,*) TRIM(file_name),"文件不存在!"
        STOP
    END IF
    OPEN(UNIT = file_id,FILE = file_name,ACCESS = 'sequential',STATUS = 'old') !顺序读取、文件已存在
    DO WHILE(.TRUE.)
        READ(UNIT = file_id,FMT = "(A79)",IOSTAT = read_stat) buffer !最多读79个字符
        IF(read_stat /= 0) EXIT
        WRITE(*,"(A79)") buffer !每读入一行后,就把这一行的文本写到屏幕上,然后READ自动换行继续读下一行
    END DO
    CLOSE(file_id)
END PROGRAM main
!用如下格式写入文件
WRITE(UNIT = file_id,FMT = "('座位号:',I2,/,'成绩:',I2)") i,score
!如果只想要读取i和score,那么与之严格对应的读取格式为:
READ(*,"(8X,I2,/,6X,I2)")

(1)文件代码通常定义成常量,在编写大型程序时,有助于修改以及分清文件。
(2)如果省略关闭文件的操作,程序结束时会自动关闭,不过还是养成手动关闭文件的习惯。
(3)文件的id在整个程序中是共享的,不同的函数可以使用同样的id来读写同一个文本文件。
(4)操作系统通常会限制一个程序所能够同时打开的文件数目,最好还是不要同时打开很多个文件。

直接访问文件

直接访问文件把文件的空间、内容事先分区成好几个同样大小的小模块,这些模块会自动编号。读写文件时要先赋值文件读写位置在第几个模块,再来进行读写操作,所以直接访问文件可以到文件的任意地方进行读写。直接访问文件的读取操作叫做直接读取

假如现在有4个学生的成绩如下,如何快速地取出第三位学生的成绩呢?这便是直接读取所要解决的问题。
在这里插入图片描述

PROGRAM main
    IMPLICIT NONE
    INTEGER,PARAMETER :: file_id = 10
    CHARACTER(LEN = 79) :: file_name = "e:\score.txt"
    INTEGER :: student
    REAL :: score
    !RECL=6表示设置每个模块的长度
    !至于为什么是6,是因为在这个文件中的每一行恰好都有4个字符
    !但是在Microsoft操作系统中,文本文件每一行的行尾都有2个看不见的符号用来代表一行文本的结束
    !(可以用来将相邻的数据分开,不至于让人看起来是一长串数字)
    !所以每行文本的长度要加2,因此是6(如果是UNIX系统,则加的是1)
    OPEN(UNIT = file_id,FILE = file_name,ACCESS = 'direct',FORM = 'formatted',RECL = 6)
    !打开直接读取文件时,OPEN命令中的ACCESS = 'direct'及RECL = 6都不能省略
    !ACCESS='direct'时,FORM的默认值是'unformatted',所以要记得加上FORM='formatted'
    WRITE(*,*) "您想要查询第几位学生的成绩:"
    READ(*,*) student
    !REC=student表示读取第student个模块
    READ(UNIT = file_id,FMT = "(F4.1)",REC = student) score
    WRITE(*,"('该学生的成绩为:',F4.1)") score
    CLOSE(file_id)
END PROGRAM main

内部文件

内部文件(Internal File)也叫做字符串变量文件

PROGRAM main
    IMPLICIT NONE
    INTEGER :: a = 2,b = 3,c;
    CHARACTER(20) :: str1,str2 = '123'
    WRITE(str1,FMT = "(I2,'+',I2,'=',I2)") a,b,a+b
    WRITE(*,"(A20)") str1 !□2+□3=□5
    READ(str2,*) c
    WRITE(*,*) c !□□□□□□□□□123
END PROGRAM main

内部文件的作用一:在使用READ命令从键盘输入数据时,如果用户输入错误的数据,会导致程序死机(例如如果需要输入整数时却输入英文字母,就可能会死机)。比较好的处理方法是程序暂时把数据当成字符串读入,检查字符串中是否含有不合理的字符,如果字符串中都是0~9的数字,就把字符串转成整数,不然就让用户重新输入。

INTEGER FUNCTION integer_input_only()
    IMPLICIT NONE
    CHARACTER(LEN = 10) :: str
    INTEGER :: i
    LOGICAL :: flag = .TRUE.
    DO WHILE(flag)
        WRITE(*,*) "请输入正整数:"
        READ(*,"(A10)") str
        flag = .FALSE.
        DO i = 1,LEN_TRIM(str)
            IF(ICHAR(str(i:i)) < ICHAR('0') .OR. ICHAR(str(i:i)) > ICHAR('9')) THEN
                WRITE(*,*) "输入错误,请重新输入!"
                flag = .TRUE.
                EXIT
            END IF
        END DO
    END DO
    READ(str,*) integer_input_only !以整型返回
    RETURN
END FUNCTION integer_input_only
    
PROGRAM main
    IMPLICIT NONE
    INTEGER,EXTERNAL :: integer_input_only
    WRITE(*,*) integer_input_only()
END PROGRAM main

内部文件的作用二:可以动态改变输出格式。输出格式可以事先放在字符串中,程序运行时,动态改变字符串的内容就可以动态改变输出格式。

PROGRAM main
    IMPLICIT NONE
    INTEGER :: a = 1,b = 2
    CHARACTER(LEN = 30) :: fmt_str = "(I??,'+',I??,'=',I??)"
    WRITE(fmt_str(3:4),"(I2.2)") INT(LOG10(REAL(a))+1)
    WRITE(fmt_str(11:12),"(I2.2)") INT(LOG10(REAL(b))+1)
    WRITE(fmt_str(19:20),"(I2.2)") INT(LOG10(REAL(a+b))+1)
    WRITE(*,fmt_str) a,b,a+b !1+2=3
END PROGRAM main

NAMELIST

NAMELIST可以把一组相关的变量封装在一起,输入/输出这一组变量时,只要在WRITE/READ中的NML字段赋值要使用哪一个NAMELIST就可以了。NAMELIST算是声明的一部分,要写在程序执行命令之前。输出NAMELIST的时候不能设置输出格式。

PROGRAM main
    IMPLICIT NONE 
    INTEGER :: a = 1,b = 2,c = 3
    NAMELIST /name_list/ a,b,c
    WRITE(*,NML = name_list)
END PROGRAM main
!&name_list
!A□□□□□□□=□□□□□□□□□□□1,
!B□□□□□□□=□□□□□□□□□□□2,
!C□□□□□□□=□□□□□□□□□□□3
!/

NAMELIST也可以用来输入数据,不过通常用来读取文件,很少用来键盘读入数据。在接下来这个例子中,用户不能随便输入3个数字了事,必须按照上面介绍的格式来输入。变量可以不按照顺序输入,程序会自动按照变量名来设置数值,变量甚至可以重复输入,不过变量会得到最后一次设置的值。

PROGRAM main
    IMPLICIT NONE
    INTEGER :: a,b,c
    NAMELIST /name_list/ a,b,c
    READ(*,NML = name_list)
    WRITE(*,NML = name_list)
END PROGRAM main
!&name_list a=1 b=2 c=3 /
!
!&name_list
!A□□□□□□□=□□□□□□□□□□□1,
!B□□□□□□□=□□□□□□□□□□□2,
!C□□□□□□□=□□□□□□□□□□□3
!/

《 F O R T R A N   S Y N T A X 》 系 列 博 客 创 作 参 考 资 料 来 源 《FORTRAN\ SYNTAX》系列博客创作参考资料来源 FORTRAN SYNTAX

  1. 《Fortran95程序设计》.彭国伦.中国电力出版社.
  2. 《工程分析程序设计》.陈斌、周屈兰.西安交通大学出版社.
  3. 《Fortran程序设计(第四版)》.Stephen J.Chapman.中国电力出版社.

博 客 创 作 : A i d e n   L e e 博客创作:Aiden\ Lee Aiden Lee
特别声明:文章仅供学习参考,转载请注明出处,严禁盗用!

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值