16  数据文件的管理

固然,我们编制一个科学计算程序的目的是执行给定的计算,是描述一个通过算法而实现的对输入数据的计算的过程,而不只是简单的对数据的处理,但是这并不妨碍我们从信息处理的角度来看待这个过程。因为任何的计算,再简单也必定包含数据的输入与输出过程,更复杂的计算程序则还包含数据的缓存管理,不同程序单位之间的数据传递,特别是在程序的计算涉及到庞大的数据量时,例如在工程计算中常见的大数组等,更加不能依靠单纯的变量来管理庞大的数据量。

实际上分析一下我们自己进行计算的情形,就知道在计算过程当中进行数据管理同样是一件非常重要的事务,而按照计算机的从冯纽曼时代就已经给予奠基的基本模型来看,一台计算机的有效工作,依赖于指令流与数据流的有机合作,因此FORTRAN语言除了要描述计算,还要能够描述对于数据流的管理。

在前面我们已经讨论了FORTRAN程序的内部通讯问题,那种通讯完全是依赖变量机制来进行的,因为那种通讯都是紧密关联于计算的通讯,直接在变量之间进行数据值的交换能够保证计算的效率和速度。但是一旦计算所涉及的数据量非常庞大,而计算过程对于数据的输入与输出要求更加复杂时,变量机制就不足以承担数据处理的功能,因此FORTRAN提供了单独的输入输出语句以及文件的概念,来实现对数据流的输入输出的管理。

除了作为面向程序自身的数据输入输出管理的功能之外,一个FORTRAN程序的完整运行还必须包括程序与人的交互,而一旦涉及到机器与人的交互,自然要求任何数据都必须以适宜于人的辨识与处理的格式出现于一定的物理媒质上,这就是输入与输出的编辑问题,将是下章所要讨论的内容,本章则只说明FORTRAN所提供的输入输出处理语句。

FORTRAN用于处理与管理输入输出数据的语句分为如下四大类:

    文件联结语句。

包括OPEN语句和CLOSE语句。

    数据传输语句。

这一类语句又可以分为2个小类别:

    据传输输入语句,包括READ语句。

    据传输输出语句,包括WRITE语句和PRINT语句。

    文件定位语句。

包括BACKSPACE语句,ENDFILE语句以及REWIND语句。

    文件查询语句。

包括INQUIRE语句。

这些语句所要实现的首要的功能,就是控制数据的输入与输出,即数据从外部媒质到内存,或从内部文件到内存的输入,以及数据从内存到外部媒质,或从内存到内部文件的输出。然后就是辅助性的用来操纵外部媒质,以及描述或查询文件与外部媒质的联结属性的功能。下面在给出FORTRAN管理数据输入输出的一般概念之后,再分别详细讨论这些语句。

16.1  输入输出管理的数据单位

FORTRAN对于输入输出数据进行管理的基本单位概念是纪录以及纪录组成的文件,因此下面我们分别讨论纪录与文件概念。

16.1.1  纪录

FORTRAN的变量一次只能存储一个数据值,显然不足以用来进行有效的数据管理,因此FORTRAN建立了专门的用来有组织地存储任意数量的数据的概念,即文件。

文件由一个纪录的序列组成,而纪录是一种逻辑形式上的单位,可以是终端或打印输出上显示的一行,也可以是外部存储器上的一个逻辑纪录,尽管纪录总是与各种物理形式的数据单位保持一定的对应,但实际上是与具体的物理表现形式无关的,因为纪录本质上是一个语法上的概念。实际上在FORTRAN里面并不存在物理纪录的概念。

组成一个文件的纪录从语法地位上分为如下两种:

    数据纪录;

    文件终止纪录。

所谓数据纪录就是作为文件的数据内容的纪录,而文件终止纪录则纯粹是一个语法意义上的纪录,它不包含任何数据内容,只是用来标志一个文件的终止。因此文件终止纪录只能用作文件的最后一个纪录,并且没有长度的属性。

由于计算机本质上的串行工作模式,纪录同样是一个串行序列的结构,该序列的单位就是数据值,即一个数据值的序列组成一个纪录。

对于数据纪录来说,其中的数据值可以有如下两种表示形式:

    无格式数据;

    格式化数据。

所谓数据的是否具有格式,完全是针对人而言的,即具有格式的数据就是把数据转化为便于人的阅读的字符型数据表示形式,也就是文字与数字,或者说ASCII编码形式;而所谓无格式数据就是FORTRAN程序自身所实际处理的数据的在物理层面上的表示形式,一般都是二进制表示的数字形式。对于计算机来说,世界上的任何形式的信息,终归都要表示为这种形式的数据。

一个FORTRAN程序所涉及到的任何数据,在该程序运行时,无论是作为运行的结果还是作为运行的初始值,它写入到内存当中,或从内存当中读出,或者是从内存到硬盘的输入输出,数据流里面的数据都是无格式数据。

而一旦数据需要人的阅读,就必须把二进制数据形式转换为能够被人阅读的字符形式,实际上我们编写的源码就是这种形式的数据。

一个数据纪录或者完全由无格式的数据组成,称为无格式纪录;或者完全由格式化数据组成,称为格式化纪录。

无格式纪录完全只是在机器内部存在,它的具体的数据形式是由系统决定的,最常见的就是二进制形式。这种纪录完全不需要人的监视与阅读,而格式化纪录则完全是人用来给机器输入数据,或机器向人展示数据结果的数据纪录形式,因此当人向机器输入格式化纪录后,机器必须再把它翻译为无格式的纪录,才能被程序所使用,反之亦然。

格式化纪录的好处就是便于人的阅读,它只能通过格式化输入输出语句来读或写;而无格式的纪录的特点就是能够直接得到机器的处理,相应的它也只能通过无格式的输入输出语句来读或写。

对于纪录可以定义长度的概念。格式化纪录的长度就是其所包含的字符的数目;而无格式纪录的长度同样用来计量其中数据量的大小,它的具体度量方法的定义则依赖于具体的处理器系统对于数据量单位的定义。格式化纪录和无格式纪录的长度都可以为0

除了包含数据值的纪录之外,还有文件终止纪录。由于它只是起文件终止的语法标志作用,因此它不包含任何数据,所以它的长度也就是0

一个文件至多只能包含一个文件终止纪录,并且只能是文件的最后一个纪录。文件终止纪录可以有如下几种生成方式:

    可以通过文件的序列访问,最后用一个ENDFILE语句显式地写下来;

    也可以通过文件定位语句,如REWIND语句或BACKSPACE语句,而隐式地写下来;

    运用CLOSE语句关闭文件或部件,或者是正常地终止程序,或者是对同一个部件使用了另外一个OPEN语句,从而隐式地写下来。

从上面的文件终止纪录的实现方式可以看出,这种纪录并不需要任何实际的物理实现。

16.1.2  文件

一个纪录的序列构成一个文件。

在程序运行的任何时候,对于一个给定的文件,它的访问方法,形式,操作以及纪录的长度,都明确地存在相应的依赖于系统的合法性规定,同时文件也可以具有字符串类型的名称,即所谓命名文件,不过对于该名称所使用的字符形式或长度,都是由具体的系统来规定,以便与相应操作系统对于文件的命名约定保持一致。

按照文件与程序的功能关系以及存储性质,文件可以分为如下两种:

    内部文件;

    外部文件。

所谓内部文件存储在程序可以访问的内存空间里面,而外部文件则存储在系统的外部存储部件上,例如硬盘。这种存储位置的不同实际上也反映了它们对于程序的不同功能,因为这两种存储空间的物理性能差异决定了它们对于CPU是具有不同意义的。

外部文件与内部文件的这种不同功能意义体现在如下几个不同的方面:

    文件的存在性。

对于外部文件来说,程序需要访问的一个外部文件可能是存在的,也可能是不存在的,都是合法的程序运行现象。例如INQUIRE语句,OPEN语句,CLOSE语句,WRITE语句,PRINT语句,REWIND语句,以及ENDFILE语句都可以引用一个并不存在的文件;而如果使用WRITE语句,PRINT语句,或ENDFILE语句来引用一个预联结的并不存在的语句,就自然地能够生成该文件。

一个外部文件的不存在也可能是来源于系统对于硬盘空间的权限限制,例如对于一个

FORTRAN应用程序来说,系统文件以及FORTRAN编译器程序文件都不应该被访问。

而对于程序来说,它所涉及的内部文件则都必须存在于相应的内存空间里面。

    程序对外部文件的访问需要通过与逻辑部件建立联结,因此就需要相应的能够对外部文件进行联结,定位与查询的语句,而对于内部文件则不需要这些语句功能。同时这种联结就使得外部文件具有定位的属性。

    对于外部文件来说,它的访问方式,合法形式,合法操作,以及合法纪录长度等都不是由FORTRAN语言标准来规定,而是由操作系统对于文件的约定以及用户的特定选择来决定的;而内部文件的内容都是作为默认字符型变量的数据值的形式而储存的,这些字符型数据值都是程序的通常的赋值过程所产生的,或者是输出语句针对变量而给出的。

如果内部文件所表示的变量是一个标量,那么该文件就只有一个纪录;如果该变量是一个数组,那么该数组的每一个元素组成该文件的一个纪录,文件里面纪录的顺序就是数组的相应的元素顺序,每个纪录的长度就是相应元素的长度。

16.1.3  文件的访问

由于文件的纪录是一种串行的序列结构,要实现对文件的纪录的访问,可以有如下两种方式:

    序列访问;

    直接访问。

所谓序列访问,就是顺着文件的纪录序列来访问特定的纪录,即如果要访问文件的第n个纪录,则需要顺次经过文件的第1,一直到第n-1个纪录,才访问到第n个纪录;而直接访问则不需要经过前面的n-1个纪录,通过指定纪录号即可直接访问第n个纪录,因此直接访问无论是读还是写,都可以按照任意的顺序进行。

这两种不同的访问方法很大程度上是由存储文件的媒质以及系统的约定等外部因素决定的,例如存储在磁带上面的可能就只允许采用序列访问的方式进行访问。

不过当一个文件被联结到了一个特定的部件之后,或者是预联结的文件被生成之后,它的访问方式就已经被决定了。

这两种不同的访问方式是由对文件的联结方式决定的,而不是属于文件自身的属性。一个文件可以只能通过序列访问方式来访问,也可以只能通过直接访问方式来访问,也可以分别通过这两种方式来访问,但不能同时用这两种方式来访问,也就是说当文件通过某个联结而被程序按照序列方式来访问,那么需要使用CLOSE语句来关闭该联结之后,再使用OPEN语句重新建立新的联结,才能换为按照直接访问的方式来访问。

能够直接访问读的纪录只限于已经写下来的纪录。

能够直接访问写的文件限于建立了直接访问联结的文件。

1. 序列访问

一个外部文件建立了序列访问的联结之后,它就具有如下的属性:

    如果针对该文件的直接访问是非法的,那么组成该文件的纪录的顺序就是写入该文件的纪录顺序;如果同时针对该文件的直接访问也是合法的,那么该文件的纪录的顺序由直接访问来决定,即序列访问该文件的第一个纪录就是直接访问该文件所指定的纪录号为1的纪录,后面顺次类推。

    文件的纪录或者全部是格式化纪录,或者全部是无格式纪录,当然有可能出现在文件最后的文件终止纪录除外。只要该文件的前一个引用不是数据传输输出语句或文件定位语句,那么文件的最后一个纪录就一定是文件终止纪录。

    文件的纪录不允许直接访问输入输出语句的读与写。

2. 直接访问

如果一个外部文件所建立的联结是直接访问,那么该文件具有如下属性:

    文件的所有纪录都具有一个唯一的纪录号,该纪录号为一个正整数,是在写纪录时给定的,而这个纪录号一旦给定,就再也不能改变。该纪录号决定了文件的纪录的顺序。

    文件的任何纪录不允许被删除,但允许被改写。

    文件的纪录或者全部是格式化纪录,或者全部是无格式纪录。

如果对于该文件序列访问方式也是合法的,那么当该文件被联结到直接访问时,它有可能包含的文件终止纪录则不被认为是属于该文件的一部分。

如果对于该文件不允许序列访问,那么该文件就不能包含文件终止纪录。

    只有通过直接访问输入输出语句才能实现对纪录的读和写。

    文件所有的纪录的长度相同。

    对于一个文件的纪录的读写顺序不一定要求按照纪录号的顺序。一旦文件与部件建立了联结,那么对于该文件的纪录的读写可以是任意顺序的。

    文件的纪录不能使用表控格式,名称列表格式,或通过非预输入输出语句来读写。

16.1.4  文件的定位

由于文件是一个数据的集合,因此程序在运行过程当中,对于文件的读写操作总是意味着程序当前所使用的数据是在发生变化的,为了描述程序当前所使用的数据或纪录,FORTRAN定义了文件的位置的概念,并且还给出了专门用来对文件位置进行操作的语句,以便实现对文件所包含的数据的精确访问与操作。

针对文件所包含的纪录的串行序列结构,以及纪录本身所包含的数据值的串行序列结构,FORTRAN定义了如下几个特征性的文件的定位情形:

    初始点。

即文件第一个纪录前面紧接该纪录的位置。如果文件定位在这个位置,那么程序对于该文件的操作将从文件的第一个纪录开始。

    终止点。

即文件最后一个纪录后面紧接该纪录的位置。如果文件定位在这个位置,那么程序接下来的操作将不进入该文件。

如果文件为空文件,即不包含任何数据,那么它的初始点和终止点相同

    对于文件的定位可以处于两个紧接的纪录中间,这时位于该位置的前面的那个纪录称为前纪录,而位于该位置的后面的那个纪录称为后纪录。当然对于初始点不存在前纪录,而对于终止点则不存在后纪录。

    对于文件的定位也可以是在输入输出语句运行时的当前纪录上面,这时该当前纪录的紧接的前面的那个纪录称为其前纪录,而该当前纪录的紧接的后面的那个纪录称为其后纪录。当然,如果文件定位不是在一个纪录里面,那么当前纪录就不存在。

当文件定位处于当前文件时,还可以更加详细地描述为定位于当前纪录的数据值序列的初始点或终止点,或纪录的任意两个数据值之间。即该纪录的紧接在数据值序列的第一个数据值前面的位置,或紧接在数据值序列的最后一个数据值后面的位置,或在数据值序列里面的任意两个数据值之间的位置。

    内部文件总是在数据传输之前定位在纪录的开始位置。

    预输入输出操作总是以纪录为单位的,因此完成这样一个操作之后,文件总是定位于一个纪录的终止位置或纪录之间的位置;而非预输入输出操作是以字符为单位的,因此完成一个非预输入输出操作之后,文件有可能定位于当前纪录的字符序列之间。

输入输出语句的运行总能影响外部文件的定位,根据作用效果的不同,输入输出语句可以分为如下两种:

    预输入输出语句。

一个预输入输出语句总是在文件的最后一个纪录完成读写之后对文件定位,除非中途发生错误。

    非预输入输出语句。

一个非预输入输出语句可以定位于当前纪录里面的字符位置,或者是随后的纪录上面。

运用非预输入输出语句就可以通过一个输入输出语句序列读写文件的纪录,其中每个语句访问纪录的一部分。这种语句也可以用来读可变长度的纪录。

在数据传输之前的文件的定位在直接访问文件与序列访问文件时有不同的约定:

    序列输入时,如果存在当前纪录,那么文件定位不变;否则文件定位于下一个纪录的头部,自然该纪录就成为了当前纪录。如果这个纪录不存在,或者在存在当前纪录,而最近访问文件的数据传输语句执行的是输出,那么该输入就不执行。

    如果文件包含文件终止纪录,那么在数据传输之前文件不能定位于文件终止纪录后面。

可以运用REWIND语句和BACKSPACE语句来对文件重定位。

    序列输出时,如果存在当前纪录,那么文件定位不会变化,当前纪录成为文件的最后纪录;如果不存在当前纪录,那么就生成下一个纪录作为文件的当前纪录,文件定位于该当前纪录的头部。

    如果是直接访问,文件的定位情形非常简单,即定位于纪录说明符所指定的纪录的头部。该纪录就是文件的当前纪录。

在数据传输过程结束之后,文件的定位有如下几种情形:

    如果数据传输过程了发生错误,那么文件定位就是不可预知的。

    如果数据传输过程没有发生错误,但是读入了文件终止纪录而导致文件终止,那么文件定位于文件终止纪录之后。

    对于非预输入如果没有出现错误,也没有出现文件终止条件,但是出现了纪录终止条件,那么文件定位于刚读入的纪录之后;如果纪录终止条件也没有出现,那么文件定位不变。

    对于非预输出如果没有出现错误,则文件定位不变。

    在所有的其他情况下,文件定位于刚读写过的纪录之后,该纪录就成为了前纪录。

16.1.5  内部文件

内部文件的概念是FORTRAN语言的一个很大的特点,它实现了数据从内存到内存的传输与转换的功能。

内部文件的属性与约定如下:

    内部文件为默认字符型变量,不能是带向量下标的数组片断。

    内部文件的纪录为标量字符变量。

    如果文件本身就是一个标量字符变量,那么该文件就只包含一个纪录,其长度就是标量字符变量的长度。

如果内部文件是一个字符数组,那么它就被看成是一个字符数组元素的序列,其中的每个元素都是该文件的一个纪录,该文件纪录的顺序就是该数组或数组片断的数组元素序,该文件的每个纪录的长度都相同,即数组元素的长度。

    写入内部文件纪录的同时就定义了该纪录。如果写入字符数目少于纪录长度,那么纪录多余的空间就被填上空字符。写入的字符数目不能超过纪录长度。

    只有在内部文件的纪录被定义之后,才能读入该纪录。

    内部文件的纪录除了通过输入语句之外,还可以使用其他方法得到定义或去定义,例如字符赋值语句也能够定义作为纪录的字符变量。

    在数据传输之前,内部文件总是定位于第一个纪录的头部,而该纪录就是当前纪录。

    在输入内部文件时,对空格的处理与使用具有值NULL的说明符BLANK=来打开外部文件一样,在必要的时候纪录可以添加空格。

    在表控输出时,字符常量不能定界。

    内部文件纪录的读与写只能通过不说明名称列表格式的序列访问格式化输入输出语句来完成。

    内部文件不能出现在文件联结语句,文件定位语句以及文件查询语句当中。

16.2  文件的部件联结与访问

程序要和文件进行通讯,都需要程序通过一定的部件联结到文件,即通过部件输出数据到文件,通过部件从文件输入数据到程序。这里的所谓部件是一个纯粹的逻辑概念,而不是一个物理概念,之所以要引入这么一个逻辑概念,主要的原因就是为了在语言里获得对输入输出的通用描述。因为我们知道文件概念实际上是与操作系统与硬件存储形式密切相关的,不同的操作系统与硬件存储形式里面,对于文件往往有不同的形式约定,因此为了使得对输入输出能够有不依赖于具体系统的描述,FORTRAN引入了部件这个逻辑概念作为数据从程序到文件之间的桥梁。

部件使用如下的语法表示方法(R901)

    io-unit

其中的输入输出部件(io-unit)可以具有如下三种形式之一:

    external-file-unit

     *

     internal-file-unit

其中外部文件部件的表示形式为标量整型表达式或者是一个星号,而内部文件部件的表示形式为默认字符型变量。

部件的一般规则如下:

表示内部文件部件的默认字符型变量不能是带有向量下标的数组片断。

一个部件可以作为外部部件也可以作为内部部件。外部部件用来联结外部文件;而内部部件用来联结内部文件。

如果表示内部文件部件的字符型变量是指针,那么该指针必须是获得了关联的。

如果表示内部文件部件的字符型变量是一个可分配数组,或者这样一个数组的子对象,那么该数组必须是当前可分配的。

表示外部文件部件的标量整型表达式必须是0或正整数。

出现在文件联结语句,文件定位语句,以及文件查询语句当中的输入输出部件只能表示外部文件部件。

在一个程序的所有程序单位里面,一个表示外部文件部件的标量整型表达式的值,表示同一个外部部件。

星号表示预先联结用来进行格式化序列访问的特定的与系统相关的外部部件。

对于一个给定程序,在任意的时间总是存在一个与系统相关的外部部件集合。所有的输入输出语句都可以使用存在的部件,而INQUIRE语句和CLOSE语句还可以使用不存在的部件。

【例16-1

        SUBROUTINE A

READ (6) X

...

SUBROUTINE B

N = 6

REWIND N

在这个程序例子里面,两个不同的程序单位里面出现的外部部件名称6表示同一个外部部件。

16.2.1  文件到部件的联结与预联结

一个外部部件可以被联结,也可以不被联结,这两种状态都是合法的。

外部部件通过预联结或通过使用OPEN语句而获得与一个外部文件的联结,正是这种联结使得外部文件能够被程序访问。这种访问也就是输入输出语句的功能所在,或者准确地说是除了OPEN语句,CLOSE语句,以及INQUIRE语句之外的所有输入输出语句因此而能够通过外部部件而访问相应的外部文件或对相应的外部文件进行操作。

文件到部件的联结与预联结的一般规则如下:

一个文件可以与部件建立联结但本身却还不存在,例如一个已经建立了预联结的文件,但可能还没有被写入。

一个部件在同一个时间不能联结多于一个文件;而一个文件也不能在同一个时间与多于一个的部件相联结。

执行CLOSE语句之后,相关的外部部件就失去了联结,然后在同一个程序单位里面,该部件仍然可以根据程序的需要再次与同一个文件或不同的文件建立联结。类似的,执行CLOSE语句之后,相关的外部文件也失去了联结,然后在同一个程序单位里面,该文件仍然可以根据程序的需要而再次与同一个部件或不同的设备建立联结。

一旦一个文件失去了联结,那么再次引用该文件的唯一方法就是在OPEN语句或INQUIRE语句里面引用该文件的名称,而如果失去联结的文件没有名称,那么就无法使得它再次获得联结。

对于内部部件来说,总联结到由标志该部件的默认字符型变量所给出的内部文件。

一旦部件与文件建立了联结,那么也就意味着建立了访问的方法,或者是序列访问,或者是直接访问。

一旦与一个已经存在的文件,或者是通过联结而生成的新文件建立联结,那么就会建立相应的格式化或非格式的数据格式。

如果联结是通过执行OPEN语句而建立的,那么在没有指定数据格式的情形下给出默认数据格式;如果联结为预联结到一个已经存在的文件,那么数据格式由预联结建立;如果预联结到一个不存在的文件,那么数据格式可以建立,也可以推迟到文件生成之后再建立,例如运行格式化或非格式的WRITE语句之后。

16.2.2  OPEN语句

OPEN语句的功能就是建立初始的外部文件与指定部件之间的联结,或者是修改该联结。具体地说,一个OPEN语句可以产生如下几种作用:

    联结一个已经存在的文件到部件;

    产生一个已经预联结的文件;

    产生一个新的文件然后把它联结到指定部件;

    改变一个文件与部件之间联结的特定说明符。

OPEN语句的语法形式(R904)为:

        OPEN ( connect-spec-list )

其中的联结说明(connect-spec)的语法形式(R905)有以下几种:

[ UNIT = ] external-file-unit

IOSTAT = scalar-default-int-variable

ERR = label

FILE = file-name-expr

STATUS = scalar-default-char-expr

ACCESS = scalar-default-char-expr

FORM = scalar-default-char-expr

RECL = scalar-int-expr

BLANK = scalar-default-char-expr

POSITION = scalar-default-char-expr

ACTION = scalar-default-char-expr

DELIM = scalar-default-char-expr

PAD = scalar-default-char-expr

其中的文件名称表达式(file-name-expr)为标量默认字符型表达式(R906)

OPEN语句的一般规则为:

    如果在部件说明符里面省略可选字符UNIT=,那么联结说明列表(connect-spec-list)的第一项必须是部件说明符。

     在一个给定OPEN语句里面,任何说明符都至多只能出现一次;其中必须给出外部文件部件(external-file-unit)

    在说明符ERR=里面给出的语句标签必须是与该OPEN语句同一个作用域单位里面的分支目标语句的标签。

    如果说明符STATUS=的值为NEWREPLACE,那么说明符FILE=必须同时给出。

如果说明符STATUS=的值为SCRATCH,那么说明符FILE=不能同时出现。

如果说明符STATUS=的值为OLD,那么说明符FILE=必须出现,除非部件当前联结到一个文件,并且该文件存在。

    说明符当中出现的标量默认字符表达式为字符的有限列表,尾部的空格被忽略。如果系统同时支持大小写,那么字符取值不区分大小写。

    在一个程序的任意程序单位里面,一旦一个外部部件通过OPEN语句获得联结,那么在该程序的任意程序单位里面都可以引用该部件。

    如果一个部件已经联结到一个存在的文件,仍然可以对该部件执行OPEN语句。如果在该OPEN语句当中不包含FILE=说明符,那么与该部件联结的文件就是已经与该部件联结的文件。

    如果与部件联结的文件并不存在,但是和已经与部件预联结的文件相同,那么由OPEN语句给出的属性成为联结的一部分。

    如果通过OPEN语句联结到部件的文件与已经与部件联结的文件不同,那么这个OPEN语句的执行效果相当于:在执行OPEN语句之前,马上执行一个不带有STATUS=说明符的CLOSE语句。

    如果通过OPEN语句联结到部件的文件与已经与部件联结的文件相同,只是当前起作用的BLANK=DELIM=PAD=ERR=,以及IOSTAT=这些说明符的值不同,那么会产生如下后果:

    如果OPEN语句当中包含POSITION=说明符,那么它的值可能与文件的当前定位不符。

    如果OPEN语句当中包含STATUS=说明符,那么它的值为OLD

    BLANK=DELIM=PAD=这些说明符的值发生作用,而其他没有出现的说明符不会发生变化,文件的定位也不会发生变化。

    此前执行的任何OPEN语句的ERR=,以及IOSTAT=这些说明符对当前执行的OPEN语句没有影响。

    如果通过OPEN语句联结到部件的文件与已经与部件联结的文件相同,那么具有值OLD的说明符STATUS=总是合法的,这时如果文件在执行OPEN语句之前的状态为SCRATCH,那么在部件关闭后,文件被删除,并且认为具有SCRATCH状态。

    如果一个文件已经与一个部件建立联结,那么对该文件运用OPEN语句使其与另外一个不同的部件建立联结是非法的。

【例16-2

OPEN (10, FILE = 'employee.names', ACTION = 'READ', PAD = 'YES')

下面更加详细地说明OPEN语句当中所使用的各种说明符的含义。

1 FILE=

    说明符FILE=的值就是与给定部件联结的文件的名称。它尾部的所有空格都被忽略。而文件名称表达式必须是系统的合法名称。

    如果在OPEN语句当中省略该说明符,并且部件也没有与文件建立联结,那么说明符STATUS=给出值SCRATCH,这时部件联结一个依赖具体系统的文件。

2 STATUS=

    其中的标量默认字符表达式取值为OLDNEWSCRATCHREPLACE,以及UNKNOWN

    当说明符取值为OLD时,文件存在,而取值为NEW时,则文件不存在。

    当具有值NEWOPEN语句成功运行之后,生成相应的文件,然后状态自然转变为OLD

    当取值为REPLACE时,如果文件不存在,那么OPEN语句生成一个新文件,然后状态取为OLD;而如果文件已经存在,则该文件被删除,OPEN语句生成一个新文件,具有与被删除文件相同的文件名称,然后状态取为OLD

    如果取值为SCRATCH,则生成文件并联结到指定的部件,以供程序使用,然后在执行引用同一个部件的CLOSE语句之后,或者是程序终止之后,该文件被删除。

    SCRATCH不能用于命名文件。

    如果取值为UNKNOWN,则具体的状态依赖于系统的约定。如果说明符被省略了,则默认值就是UNKNOWN

3 ACCESS=

    其中标量默认字符表达式的取值为SEQUENTIALDIRECT。分别表示文件联结的访问方法为序列访问或直接访问。

    如果该说明符被省略,则默认取值为SEQUENTIAL

    如果联结文件已经存在,那么该说明符指定的访问方法必须对于该文件是合法的。

    如果文件不存在而需要生成新文件,那么说明符指定的访问方法必须对于该新文件是合法的。

4 FORM=

    其中标量默认字符表达式取值为FORMATTEDUNFORMATTED。分别表示文件联结为格式化输入输出或无格式输入输出。

    如果该说明符被省略了,那么在文件联结为直接访问时,默认值为UNFORMATTED;而如果文件联结为序列访问时,默认值为FORMATTED

    如果联结文件已经存在,那么该说明符指定的格式必须对于该文件是合法格式。

    如果文件不存在而需要生成新文件,那么说明符指定的格式必须对于该新文件是合法格式。

5 RECL=

    该说明符的取值必须为正整数。在文件联结为直接访问的情况下,该取值表示文件的每个纪录的长度;在文件联结为序列访问的情况下,该数值表示文件的所有纪录当中最大的长度。

    在文件联结为直接访问时,该说明符必须给出。

    在文件联结为序列访问时,该说明符可以省略,默认值依赖于系统的约定。

    如果文件联结为格式化输入输出,那么取值为只包含默认字符型字符的纪录的字符数目。如果纪录里面包含了非默认字符型,那么该说明符的取值依赖于系统的约定。

    如果文件联结为无格式输入输出,那么纪录长度由系统约定的度量单位来决定具体数值。

    如果联结文件已经存在,那么该说明符指定的长度必须对于该文件是合法长度。

    如果文件不存在而需要生成新文件,那么说明符指定的长度必须对于该新文件是合法长度。

6 BLANK=

    其中标量默认字符表达式的取值为NULLZERO

    BLANK=说明符只能用于格式化输入输出的文件联结。

    如果取值为NULL,那么在给定部件的数值格式化输入域里面的所有空格字符都被忽略,除非全部为空格的域具有零值。

    如果取值为ZERO,那么除了头部的空格之外,所有其他空格都被视为0

    如果该说明符省略了,那么默认值为NULL

7. POSITION=

    其中标量默认字符表达式的取值为ASISREWIND,或APPEND。该说明符只能用于序列访问的联结。

    一个新生成的文件总是定位于初始点。

    REWIND使得一个已经存在的文件定位于它的初始点。

    APPEND使得一个已经存在的文件定位于文件终止纪录的前纪录,而如果该文件不包含文件终止纪录,则定位于该文件的终止点。

    如果文件存在并且已经联结,那么ASIS使得它的定位不变,而如果文件存在但没有联结,那么ASIS表示它的定位未知。如果该说明符被省略,那么默认值为ASIS

8. ACTION=

    其中标量默认字符表达式可以取值为READWRITEREADWRITE

    取值READ表示WRITEPRINT,以及ENDFILE语句都不能引用该联结。

    取值WRITE表示READ语句不能引用该联结。

    取值READWRITE表示任何输入输出语句都可以引用该联结。

    如果该说明符省略了,则默认值依赖于系统的约定。

    如果文件的合法操作里面包含了READWRITE,那么也应该包含READWRITE

    如果联结文件已经存在,那么该说明符指定的操作必须对于该文件是合法操作。

    如果文件不存在而需要生成新文件,那么说明符指定的操作必须对于该新文件是合法操作。

9. DELIM=

    该说明符只能用于具有格式化输入输出联结的文件。在输入格式化纪录时该说明符被忽略。

    其中标量默认字符表达式可以取值为APOSTROPHEQUOTENONE

    如果取值为APOSTROPHE,则表控或名称列表格式写入的字符值的分隔必须使用撇号;而内部撇号则必须使用双撇号。

    如果取值为QUOTE,那么表控或名称列表格式写入的字符值的分隔必须使用引号;而内部引号则必须使用双引号。

    如果取值为NONE,那么写入字符不能使用撇号或引号作为分隔标志,内部撇号或引号也不能是双的。

    如果该说明符被省略了,那么默认取值为NONE

10. PAD=

    该说明符只能用于具有格式化输入输出联结的文件。在格式化纪录输出时,该说明符被忽略。

    其中的标量默认字符表达式可以取值为YESNO

    如果取值为YES,那么在给出了输入列表,并且格式说明要求纪录包含比它本来具有的数据更多的数据时,该格式化输入纪录可以在尾部添加足够的空格。

    如果取值为NO,那么输入列表以及格式说明都不能要求纪录具有比它本来具有的数据更多的数据。

    如果该说明符被省略,那么默认取值为YES

    对于非默认字符型数据,对于附加的空格字符由系统约定。

16.2.3  CLOSE语句

CLOSE语句的功能为终止一个给定部件到一个外部文件的联结。

CLOSE语句的一般语法形式(R907)为:

        CLOSE ( close-spec-list )

其中的关闭说明(close-spec)可以是如下几种形式(R908)之一:

[ UNIT = ] external-file-unit

IOSTAT = scalar-default-int-variable

ERR = label

STATUS = scalar-default-char-expr

CLOSE语句的一般规则为:

    如果在部件说明当中省略了字符UNIT=,那么部件说明符必须是关闭说明列表的第一项.

    在一个给定关闭说明里面,任何说明符都只能出现一次,其中必须给出外部文件部件。

    出现在说明符ERR=当中的语句标签,必须是在和CLOSE语句同一个作用域单位里面的分支目标语句的标签。

    其中的标量默认字符表达式取值为字符型数据,其尾部的空格都被忽略。如果系统同时支持大小写,那么不区分字符的大小写。

    在程序的任何程序单位里面都可以对某个部件执行CLOSE语句,但是不能在同一个作用域单位里面和OPEN语句作用于同一个部件。

    针对一个不存在的部件,或者是一个没有与文件联结的部件执行CLOSE语句是合法的,但是不影响任何文件。

    在一个作用域单位里面,如果一个部件被CLOSE语句关闭联结之后,仍然可以再次和原来的文件,或者是另外的文件建立联结。

    在一个作用域单位里面,如果一个命名文件被CLOSE语句关闭联结,那么它仍然可以在该程序单位里面和同一个部件,或者另外的部件建立联结,只要该文件一直存在。

    程序的执行正常终止之后,所有的部件联结都被关闭。如果在终止之前文件状态为SCRATCH,那么关闭之后部件状态为DELETE;其他情形下关闭之后的部件状态为KEEP

【例16-3

         CLOSE (10, STATUS = 'KEEP')

CLOSE语句的STATUS=说明符遵循如下规则:

    其中的标量默认字符表达式可以取值为KEEPDELETE,分别表示是否保留与给定部件联结的文件。

    KEEP不能用于在执行CLOSE语句之前状态为SCRATCH的文件。

    如果KEEP用于一个存在的文件,那么在执行CLOSE语句之后,该文件继续存在。

    如果KEEP用于一个不存在的文件,那么在执行CLOSE语句之后,该文件仍然不存在。

    如果取值为DELETE,那么在执行CLOSE语句之后,文件不再存在。

    如果该说明符被省略,那么默认值为KEEP,除非文件在执行CLOSE语句之前状态为SCRATCH,如果出现那种情况,则默认值为DELETE

16.3  文件的传输

文件传输语句包括如下三种:

    READ语句,为数据输入语句;

    WRITE语句和PRINT语句,为数据输出语句。

READ语句的一般语法形式(R909)为以下两种形式之一:

READ ( io-control-spec-list ) [ input-item-list ]

READ format [ , input-item-list ]

WRITE语句的一般语法形式(R910)为:

WRITE ( io-control-spec-list ) [ output-item-list ]

PRINT语句的一般语法形式(R911)为:

PRINT format [ , output-item-list ]

对于其中的输入输出控制说明列表(io-control-spec-list)和数据输入输出项列表(input/output-item-list)在下面分节予以说明。

【例16-4

READ (6, *) SIZE

READ 10, A, B

WRITE (6, 10) A, S, J

PRINT 10, A, S, J

10 FORMAT (2E16.3, I5)

16.3.1  控制信息列表

所谓输入输出控制说明列表就是控制信息列表,用来控制数据的传输,包括如下的成分:

    数据传输的源或目标;

    可选的编辑过程的说明;

    可选的确定纪录的说明;

    可选的对于需要排除的操作的说明;

    可选的状态返回;

    可选的纪录预说明;

    可选的读入字符数目返回。

输入输出控制说明的一般语法形式(R912)有如下几种:

[ UNIT = ] io-unit

[ FMT = ] format

[ NML = ] namelist-group-name

REC = scalar-int-expr

 IOSTAT = scalar-default-int-variable

 ERR = label

 END = label

 ADVANCE = scalar-default-char-expr

 SIZE = scalar-default-int-variable

 EOR = label

按照控制信息列表所包含的内容的不同,数据传输语句可以分为两种:

    如果数据传输语句包含了格式说明或名称列表集合名称,那么该语句就属于格式化输入输出语句。

    否则就属于无格式输入输出语句。

控制信息列表的一般规则为:

    在上面列举的输入输出控制说明当中必须包含一个,也至多包含一个输入输出部件,而其他的说明选项至多出现一次。

    WRITE语句当中不能出现END=EOR=,以及SIZE=说明符。

    出现在说明符ERR=EOR=,以及END=里面的语句标签必须该数据传输语句所在的作用域单位里面的分支目标语句的标签。

    如果在数据传输语句当中出现了输入输出项列表,那么就不能同时出现名称列表集合名称。

    一个输入输出控制说明列表里面不能同时包含一个格式说明和一个名称列表集合名称。

    如果部件说明符里面省略了字符UNIT=,那么控制信息列表的第一项必须是部件说明符。

    如果在格式说明符里面省略了字符FMT=,那么控制信息列表的第二项必须是格式说明符,而控制信息列表的第一项必须是不带可选字符UNIT=的部件说明符。

    如果在名称列表说明符里面省略了字符NML=,那么控制信息列表的第二项必须是名称列表说明符,而控制信息列表的第一项必须是不带可选字符UNIT=的部件说明符。

    如果部件说明符给出的是一个内部文件,那么输入输出控制说明列表不能包含说明符REC=,也不能包含名称列表集合名称。

    如果语句当中给出了说明符REC=,那么其中就不能出现说明符END=和名称列表集合名称,如果出现格式说明,则不能是星号表示的表控输入输出。

    说明符ADVANCE=只能出现在具有显式格式说明的格式化序列输入输出语句里面,其控制信息列表不包含内部文件的部件说明符。

    如果出现了EOR=说明符,那么说明符ADVANCE=也必须同时出现。

    如果出现了SIZE=说明符,那么说明符ADVANCE=也必须同时出现。

    说明符SIZE=只能出现在包含取值为NO的说明符ADVANCE=的输入语句当中。

    说明符EOR=只能出现在包含取值为NO的说明符ADVANCE=的输入语句当中。

    如果数据传输语句的IOSTAT=SIZE=说明符里面给出了变量,那么该变量不能关联于数据传输输入输出列表里面的任何数据对象,也不能关联于名称列表集合对象列表里面的任何数据对象,也不能关联于数据传输输入输出列表里面的隐式输入输出do结构里的do变量。

    在数据传输语句里面,如果由说明符IOSTAT=或者说明符SIZE=给出的变量为数组元素引用,那么数据传输,隐式输入输出do过程,或者在输入输出控制说明列表里面的其他说明符定义或赋值,都不影响其下标值。

【例16-5】下面给出一个READ语句的例子。

    READ (IOSTAT = IOS, UNIT = 6, FMT = '(10F8.2)') A, B

下面我们分节说明控制信息列表的各种说明符以及相关内容。

1. 格式说明符FMT=

说明符FMT=的功能为在格式化输入输出语句当中提供格式说明,或提供表控格式。 它的一般语法形式(R913)

default-char-expr

label

其中的标签(label)必须是出现在同一个作用域单位里面的包含了格式说明符的作为FORMAT语句的标签。

其中的默认字符表达式(default-char-expr)表示一个有效的格式说明。该表达式也可以是一个特殊的字符常量,注意参考第7章里面对于表达式的说明。如果该表达式是一个数组的形式,那么可以把该数组看成是所有的数组元素按照数组元素序串联起来。

如果格式表示是其中的星号*,那么该语句就是所谓的表控输入输出语句。

【例16-6

        READ (6, FMT = "(" // CHAR_FMT // ")" ) X, Y, Z

在这个例子里面格式为字符表达式,其中CHAR_FMT为一个默认字符变量。

2. 名称列表说明符NML=

说明符NML=给出名称列表集合名称。该名称表示了一个需要进行数据传输操作的数据对象的集合。

如果语句当中给出了这个名称列表集合名称,那么该语句就是所谓名称列表输入输出语句。

3. 纪录数说明符REC=

纪录数说明符The REC=给出需要读写的纪录的数目。

该说明符只能用于针对直接访问联结部件的输入输出语句,因此这个说明符可以说是一个标志性的东西,即只要控制信息列表里面包含了REC=说明符,那么该语句就是所谓直接访问输入输出语句,否则就是所谓序列访问输入输出语句。

4. 输入输出状态说明符IOSTAT=

执行一个包含了IOSTAT=说明符的输入输出语句实际上也就是定义了在IOSTAT=说明符里面给出的变量。

该变量的取值情况有如下几种:

    如果语句执行过程当中没有出现错误条件,也没有出现文件终止条件和纪录终止条件,那么变量取值为0

    如果出现错误条件,那么取值为系统约定的正整数值。

    如果出现文件终止条件,而没有出现错误条件,那么取值为系统约定的负整数值。

    如果出现纪录终止条件,而没有出现错误条件与文件终止条件,那么取值为系统约定的不同于文件终止条件下的取值的负整数值。

只有在执行序列输入语句时才会出现文件终止条件,而只有在执行非预输入语句时才会出现纪录终止条件,参见下面的例子。

【例16-7

        READ (FMT = "(E8.3)", UNIT = 3, IOSTAT = IOSS) X

IF (IOSS < 0) THEN

! 对联结到部件3的文件进行文件终止操作.

CALL END_PROCESSING

ELSE IF (IOSS > 0) THEN

! 进行出错处理

CALL ERROR_PROCESSING

END IF

5. 出错分支处理

如果在执行一个包含了说明符ERR=的输入输出语句时出现了错误条件,就会导致如下的分支后果:

    输入输出语句执行中断;

    输入输出语句给出的文件定位不可确定;

    如果该输入输出语句还包含了IOSTAT=说明符,那么其中给出的变量取值为系统约定的正整数值。

    如果执行的语句是READ语句,并且包含了SIZE=说明符,那么变量取值整数值;

    继续执行由ERR=说明符给出的语句。

6. 文件终止时的分支处理

如果在执行包含了END=说明符的输入语句时出现了文件终止条件,但没有出现错误条件,那么会导致如下分支后果:

    输入语句的执行中断;

    如果输入语句中指定的文件是外部文件,那么它定位在文件终止纪录的后面。

    如果输入语句包含了说明符IOSTAT=,那么其中给出的变量取值为系统约定的负整数值。

    继续执行由END=说明符给出的语句。

7. 纪录终止时的分支处理

如果在执行包含了EOR=说明符的输入输出语句时出现了纪录终止条件,但没有出现错误条件,那么会导致如下分支后果:

    如果语句当中包含的说明符PAD=的取值为YES,那么纪录被添加上空格,以便满足输入列表项及其数据编辑描述符对于纪录字符数目的要求。

    输入语句的执行中断。

    输入语句给出的文件定位于当前纪录后面。

    如果输入语句包含了说明符IOSTAT=,那么其中给出的变量取值为系统约定的负整数值。

    如果输入语句包含了说明符SIZE=,那么其中给出的变量取值为整数值。

    继续执行由EOR=说明符给出的语句。

8. ADVANCE=说明符

其中的标量默认字符表达式(scalar-default-char-expr)可以取值为YESNO

该说明符用来说明是否在输入输出语句当中出现非预输入输出。如果取值为NO,则出现非预输入输出;如果取值为YES,那么出现预格式化序列输入输出。

如果该说明符省略了,那么默认取值为YES

9. 字符数目说明符SIZE=

当非预输入语句中断之后,在说明符SIZE=当中给出的变量,取值为在当前输入语句执行过程当中由数据编辑描述符传输的字符数目。

其中填充的空格不计入该字符数目值。

16.3.2  数据传输的输入输出列表

一个所谓输入输出列表给出通过数据传输输入输出语句传输了数据值的数据项。

其中输入项(input-item)的一般语法形式(R914)为:

variable

io-implied-do

其中输出项(output-item)的一般语法形式(R915)为:

expr

io-implied-do

其中隐式输入输出do结构(io-implied-do)的一般语法形式(R916)为:

( io-implied-do-object-list , io-implied-do-control )

而里面的隐式do对象(io-implied-do-object)的语法形式(R917)为:

input-item

output-item

里面的隐式输入输出do控制(io-implied-do-control)的语法形式(R918)为:

do-variable = scalar-int-expr , &

& scalar-int-expr [ , scalar-int-expr ]

输入输出列表的一般规则为:

    作为输入项的变量不能是完全哑尺度数组。

    do变量必须是整型的命名标量变量。

    在输入项列表(input-item-list)里面,隐式输入输出do对象(io-implied-do-object)

    必须是一个输入项。

    在输出项列表(output-item-list)里面,隐式输入输出do对象(io-implied-do-object)

    必须是一个输出项。

    如果某个输入项为指针,那么它必须当前关联于一个可定义的目标数据对象,并且数据从文件传输到关联目标。

如果某个输出项为指针,那么它必须当前关联于一个可定义的目标数据对象,并且数据从关联目标传输到文件。

    一个输入项不能是一个包含输入项的隐式输入输出do结构的do变量,也不能关联于这样的do变量。

    一个派生数据类型的对象,如果它的成员里面包含了指针,则不能作为输入输出列表里面的数据项。因为指针成员的值只是对于内存地址的一个描述符,因此不具有独立于系统的表示方法。

    如果输入项或输出项为可分配数组,那么它的当前状态应该是已分配。

    包含在一个隐式输入输出do结构里面的隐式输入输出do结构的do变量,不能是其宿主结构的do变量,也不能关联于这样的do变量。

    如果是输入输出列表里面出现了数组作为列表项,那么其中的元素按照数组元素序的顺序加以说明。

    数组的元素都不影响输入项里面任何表达式的值,任何元素都不能在输入项里面重复出现。

    输入输出列表当中的隐式do结构的循环初始化和执行过程与DO结构的一样。

    如果输入输出语句说明的是内部文件,那么输入输出列表不能包含非默认字符类型的数据对象。

    常量,包含算符或函数引用的表达式,以及括号当中的表达式都可以出现在输出列表里面,但不能出现在输入列表里面。

【例16-8】下面的例子里面既有合法的形式也有不合法的形式。

INTEGER A (100), J (100)

...

READ *, A (A) ! 非法

READ *, A (LBOUND (A, 1) : UBOUND (A, 1)) !合法

READ *, A (J) ! 如果J的元素都不重复则是合法的

READ *, A (A (1) : A (10)) ! 非法

【例16-9

WRITE (LP, FMT = '(10F8.2)') (LOG (A (I)), I = 1, N + 9, K), G

这个例子的输出列表里面包含了一个隐式do结构。

16.3.3  数据传输输入输出语句的执行

执行一个数据传输输入输出语句的完整过程如下:

(1) 决定数据传输的方向;

(2) 确定相应的部件;

(3) 如果要求格式则建立相应的格式;

(4) 在文件传输之前对文件定位;

(5) 在文件与输入输出列表或名称列表里面给出的数据项之间进行数据传输;

(6) 随时判别是否出现错误条件,文件终止条件,以及纪录终止条件;

(7) 在数据传输完成之后,再次对文件进行定位;

(8) 对说明符IOSTAT=SIZE= 里面的变量定义恰当的值。

16.3.4  格式化纪录的打印

把格式化之后的纪录传输给系统设置的外部设备就称为打印。

在打印一个格式化纪录的时候,纪录的第一个字符是格式说明,不被打印出来,而纪录的其他字符都打印在一行上。

纪录的第一个字符必须是默认字符型数据,它的功能在于决定竖直方向的行距,列举如下表16-1

16-1  纪录字符所表示的行距

纪录的第一个字符

空格

1

0

2

1

下页的第一行

+

没有前面行

  

如果纪录不包含任何字符,那么行距为1行,并且除了空格之外,在该行上不打印任何字符。

PRINT语句并不意味着打印开始,WRITE语句也不意味着打印开始,它们都只是起到类似记账的作用。

16.3.5  数据传输语句的终止

当出现如下的情况时,数据传输输入输出语句的执行都被中断:

    格式处理遇到一个数据编辑描述符,而同时在输入输出项列表里面不再包含任何元素。

    无格式的数据或表控数据的传输完成整个输入项列表或输出项列表的所有项目。

    名称列表输出完成整个名称列表集合对象列表(namelist-group-object-list)里面的所有项目。

    出现错误条件。

    出现文件终止条件。An end-of-file condition occurs.

    在表控输入或名称列表输入时,读入纪录遇到了作为值分隔符的斜线(/)

    在执行非预输入语句时,出现了纪录终止条件。

16.4  文件的定位

文件的定位语句包括BACKSPACE语句,ENDFILE语句和REWIND语句,它们的语法形式如下。

BACKSPACE语句的语法形式(R919)为:

BACKSPACE external-file-unit

BACKSPACE ( position-spec-list )

ENDFILE语句的语法形式(R920)

ENDFILE external-file-unit

ENDFILE ( position-spec-list )

REWIND语句的语法形式(R921)为:

REWIND external-file-unit

REWIND ( position-spec-list )

其中的定位说明(position-spec)的语法形式(R922)为:

[ UNIT = ] external-file-unit

IOSTAT = scalar-default-int-variable

ERR = label

文件的定位的一般规则如下:

● ERR=说明符里面的标签必须是处于与文件定位语句同一个作用域单位的分支目标语句的标签。

如果在部件说明符里面省略了可选的字符UNIT=,那么定位说明列表的第一项必须是部件说明符。

定位说明列表里面必须包含且只能包含一个外部文件部件,并且每个说明符只能至多出现一次。

没有联结为序列访问的文件不能用于这三个定位语句,而具有ACTION=说明符,并且取值为READ的联结的文件不能用于ENDFILE语句。

16.4.1  BACKSPACE语句

执行一个BACKSPACE语句,那么文件联结到给定部件,文件定位则有如下三种情形:

    如果文件存在当前纪录,定位于当前部件前。

    如果不存在当前纪录,则定位于前纪录前面。

    如果不存在当前纪录,也不存在前纪录,那么文件定位不变。

如果前纪录为文件终止纪录,那么文件定位于文件终止纪录前面。

如果BACKSPACE语句导致隐式写入文件终止纪录,那么文件定位于文件终止纪录之前的那个纪录。

【例16-10】下面是BACKSPACE语句的一个例子。

      BACKSPACE (10, ERR = 20)

16.4.2  ENDFILE语句

ENDFILE语句的功能是写入一个文件终止纪录作为文件下一个纪录,然后文件定位于该文件终止纪录后面,而该文件终止纪录就成为了该文件的最后一个纪录。

如果该文件也能够被联结为直接访问,那么只有在该文件终止纪录之前的纪录是真实写入了的,因此也就只有这些纪录能够被随后的直接联结读到。

在执行ENDFILE语句之后,还可以在执行任何的数据传输输入输出语句之前应用BACKSPACE语句或REWIND语句来改变文件的定位。

针对一个联结了但是并不存在的文件执行ENDFILE语句,将在写入文件终止纪录之前产生该文件。

【例16-11

    ENDFILE K

这是一个简单的ENDFILE语句的例子。

16.4.3  REWIND语句

执行REWIND语句的效果就是使得给定的文件被定位于它的初始点。

如果文件本来就已经定位于它的初始点,那么再执行REWIND语句将不会对它的定位产生任何影响。

针对一个联结了但并不存在的文件执行REWIND语句是合法的,但是并不能产生任何的影响。

【例16-12

    REWIND 10

这是一个REWIND语句的简单例子。

16.5  文件的查询

INQUIRE语句的功能为查询特定命名文件或与特定部件的联结的属性。

INQUIRE语句具有三种形式:

    文件查询形式。

这种查询形式使用说明符FILE=

    部件查询形式。

这种查询形式使用说明符UNIT=

    输出列表查询。

这种查询形式使用说明符IOLENGTH=

所有这些说明符的赋值规则都遵循一般的赋值语句的规则。

INQUIRE语句可以在文件的任何联结状态之下执行,INQUIRE语句返回的值反映当前被执行的语句的文件状态。

INQUIRE语句的一般语法形式(R923)

 INQUIRE ( inquire-spec-list )

INQUIRE ( IOLENGTH = scalar-default-int-variable ) &

&output-item-list

【例16-13

    INQUIRE (IOLENGTH = IOL) A (1:N)

INQUIRE (UNIT = JOAN, OPENED = LOG_01, NAMED = LOG_02, &

FORM = CHAR_VAR, IOSTAT = IOS)