NAG Fortran Compiler, Release 7.2: Input/output Features

Navigation: Previous Up Next

## 9.7 Input/output Features

### 9.7.1 Stream input/output [5.1]

A stream file is a file that is opened with the `ACCESS='STREAM'` specifier. A stream file is either a formatted stream or an unformatted stream.

A formatted stream file is equivalent to a C text stream; this acts much like an ordinary sequential file, except that there is no limit on the length of a record. Just as in C, when writing to a formatted stream, an embedded newline character in the data causes a new record to be created. The new intrinsic enquiry function `NEW_LINE(A)` returns this character for the kind (character set) of `A`; if the character set is ASCII, this is equal to `IACHAR(10)`. For example,

      OPEN(17,FORM='formatted',ACCESS='stream',STATUS='new')
      WRITE(17,'(A)'), 'This is record 1.'//NEW_LINE('A')//'This is record 2.'

An unformatted stream file is equivalent to a C binary stream, and has no record boundaries. This makes it impossible to `BACKSPACE` an unformatted stream. Data written to an unformatted stream is transferred to the file with no formatting, and data read from an unformatted stream is transferred directly to the variable as it appears in the file.

When reading or writing a stream file, the `POS=` specifier may be used to specify where in the file the data is to be written. The first character of the file is at position 1. The `POS=` specifier may also be used in an `INQUIRE` statement, in which case it returns the current position in the file. When reading or writing a formatted stream, the `POS=` in a `READ` or `WRITE` shall be equal to 1 (i.e. the beginning of the file) or to a value previously discovered through `INQUIRE`.

Note that unlike unformatted sequential files, writing to an unformatted stream file at a position earlier than the end of the file does not truncate the file. (However, this truncation does happen for formatted streams.)

Finally, the `STREAM=` specifier has been added to the `INQUIRE` statement. This specifier takes a scalar default character variable, and assigns it the value `'YES'` if the file may be opened for stream input/output (i.e. with `ACCESS='STREAM'`), the value `'NO'` if the file cannot be opened for stream input/output, and the value `'UNKNOWN'` if it is not known whether the file may be opened for stream input/output.

### 9.7.2 The BLANK= and PAD= specifiers [5.1]

The `BLANK=` and `PAD=` specifiers, which previously were only allowed on an `OPEN` statement (and `INQUIRE`), are now allowed on a `READ` statement. These change the `BLANK=` or `PAD=` mode for the duration of that `READ` statement only.

### 9.7.3 Decimal Comma [5.1]

It is possible to read and write numbers with a decimal comma instead of a decimal point. Support for this is provied by the `DECIMAL=` specifier and the `DC` and `DP` edit descriptors. The `DECIMAL=` specifier may appear in `OPEN`, `READ`, `WRITE` and `INQUIRE` statements; possible values are `'POINT'` (the default) and `'COMMA'`. For an unconnected or unformatted unit, `INQUIRE` returns `'UNDEFINED'`. The `DC` edit descriptor temporarily sets the mode to `DECIMAL='COMMA'`, and the `DP` edit descriptor temporarily sets the mode to `DECIMAL='POINT'`.

When the mode is `DECIMAL='COMMA'`, all floating-point output will produce a decimal comma instead of a decimal point, and all floating-point input will expect a decimal comma. For example,

      PRINT '(1X,"Value cest ",DC,F0.2)',1.25

will produce the output

     Value cest 1,25

Additionally, in this mode, a comma cannot be used in list-directed input to separate items; instead, a semi-colon may be used.

### 9.7.4 The DELIM= specifier [5.1]

The `DELIM=` specifier, which previously was only allowed on an `OPEN` statement (and `INQUIRE`), is now allowed on a `WRITE` statement. It changes the `DELIM=` mode for the duration of that `WRITE` statement; note that this only has any effect if the `WRITE` statement uses list-directed or namelist output. For example,

      WRITE(*,*,DELIM='QUOTE') "That's all folks!"

will produce the output

     'That''s all folks!'

### 9.7.5 The ENCODING= specifier [5.1]

The `ENCODING=` specifier is permitted on `OPEN` and `INQUIRE` statements. Standard values for this specifier are `'UTF-8'` and the default value of `'DEFAULT'`; the `'UTF-8'` value is only allowed on compilers that support a Unicode character kind (see `SELECTED_CHAR_KIND`). This release of the NAG Fortran Compiler supports `'DEFAULT'` and `'ASCII'`.

### 9.7.6 The IOMSG= specifier [5.1]

The `IOMSG=` specifier has been added to all input/output statements. This takes a scalar default character variable, which in the event of an error is assigned an explanatory message. (Note that this is only useful if the statement contains an `IOSTAT=` or `ERR=` specifier, otherwise the program will be terminated on error anyway.) If no error occurs, the value of the variable remains unchanged.

### 9.7.7 The IOSTAT= specifier [5.1]

This now accepts any kind of integer variable (previously this was required to be default integer).

### 9.7.8 The SIGN= specifier [5.1]

The `SIGN=` specifier has been added to the `OPEN`, `WRITE` and `INQUIRE` statements; possible values are `'PLUS'`, `'SUPPRESS'` and `'PROCESSOR_DEFINED'` (the default). For the NAG Fortran Compiler, `SIGN='PROCESSOR_DEFINED'` has the same effect as `SIGN='SUPPRESS'`.

The effect of `SIGN='PLUS'` is the same as the `SP` edit descriptor, the effect of `SIGN='SUPPRESS'` is the same as the `SS` edit descriptor, and the effect of `SIGN='PROCESSOR_DEFINED'` is the same as the `S` edit descriptor.

### 9.7.9 Intrinsic functions for testing IOSTAT= values [5.1]

The intrinsic functions `IS_IOSTAT_END` and `IS_IOSTAT_EOR` test `IOSTAT=` return values, determining whether a value indicates an end-of-file condition or an end-of-record condition. These are equivalent to testing the `IOSTAT=` return value against the named constants `IOSTAT_END` and `IOSTAT_EOR` respectively; these constants are available through the `ISO_FORTRAN_ENV` module.

### 9.7.10 Input/output of IEEE infinities and NaNs [5.1]

Input and output of IEEE infinities and NaNs is possible: the output format is

- `-Infinity` (or `-Inf` if it will not fit) for negative infinity;
- `Infinity` (or `Inf` if it will not fit) for positive infinity, or `+Infinity` (or `+Inf`) with `SP` or `SIGN='PLUS'` mode;
- `NaN` for a NaN.

Furthermore, the output is right-justified within the output field. For list-directed output the output field is the minimum size to hold the result.

Input of IEEE infinities and NaNs is now possible; these take the same form as the output described above, except that:

- case is not significant,
- a NaN may be preceded by a sign, which is ignored, and
- a NaN may be followed by alphanumeric characters enclosed in parentheses (the NAG Fortran Compiler also ignores these).

The result of reading a NaN value in NAG Fortran is always a quiet NaN, never a signalling one.

### 9.7.11 Output of floating-point zero [5.1]

List-directed and namelist output of floating-point zero is now done using F format instead of E format. (The Fortran 90 and 95 standards both specified E format.)

### 9.7.12 NAMELIST and internal files [5.1]

Namelist input/output is now permitted to/from internal files.

### 9.7.13 Variables permitted in NAMELIST

All variables except for assumed-size arrays are now permitted to appear in a namelist group [6.0 for allocatable and pointer, 5.3.1 for the rest]. Note that an allocatable variable that appears in a namelist group must be allocated, and a pointer variable that appears in a namelist group must be associated, when a `READ` or `WRITE` statement with that namelist is executed. Also, if a variable is polymorphic or has an ultimate component that is allocatable or a pointer, it is only permitted in a namelist when it will be processed by defined input/output (see below).

### 9.7.14 Recursive input/output [5.2]

Input/output to internal files is now permitted while input/output to another internal file or an external file is in progress. This occurs when a function in an input/output list executes an internal file `READ` or `WRITE` statement.

Input/output to an external file while external file input/output is already in progress remains prohibited, except for the case of nested data transfer (see “Defined input/output”).

### 9.7.15 Asynchronous input/output

#### 9.7.15.1 Basic syntax [5.1]

Asynchronous input/output syntax is accepted; this consists of the `ASYNCHRONOUS=` specifier on `OPEN`, `READ`, `WRITE` and `INQUIRE`, the `ID=` specifier on `READ`, `WRITE` and `INQUIRE`, and the `PENDING=` specifier on `INQUIRE`.

Except for the `INQUIRE` statement, the `ASYNCHRONOUS=` specifier takes a scalar default character expression; this must evaluate either to `'YES'` or `'NO'`, treating lowercase the same as uppercase. In the `READ` and `WRITE` statements, this character expression must be a constant expression, and the statement must refer to an external file whose connection allows asynchronous input/output; if `ASYNCHRONOUS='YES'` is specified, the data transfer may occur asynchronously. In the `OPEN` statement, this specifier determines whether asynchronous data transfer is allowed for that file: the default setting is `'NO'`. For the `INQUIRE` statement, the `ASYNCHRONOUS=` specifier takes a scalar default character variable, and sets it to `'YES'` if the file is currently connected for asynchronous input/output, `'NO'` if the current connection does not allow asynchronous input/output and `'UNKNOWN'` if the file is not connected.

For the `READ` and `WRITE` statements, the `ID=` specifier takes a scalar integer variable. This specifier is only permitted if `ASYNCHRONOUS='YES'` also appears. The integer variable is assigned the “identifier” of the asynchronous data transfer that the `READ` or `WRITE` initiates; this value can be used in `INQUIRE` and `WAIT` statements to track the progress of the asynchronous data transfer.

For the `INQUIRE` statement, the `ID=` specifier takes a scalar integer expression whose value must be that returned from `ID=` on a `READ` or `WRITE` statement for that file, and is only permitted in conjunction with the `PENDING=` specifier. The `PENDING=` specifier takes a scalar default logical variable and sets it to `.TRUE.` if the specified asynchronous data transfer is still underway and to `.FALSE.` if it has completed. If `PENDING=` is used without `ID=`, the enquiry is about all outstanding asynchronous data transfer on that file.

After initiating an asynchronous data transfer, the variables affected must not be referenced or defined until after the transfer is known to have finished. For an asynchronous `WRITE` of a local variable, this means not returning from the procedure until after ensuring the transfer is complete. An asynchronous data transfer is known to have been finished if there is a subsequent synchronous data transfer, an `INQUIRE` statement which returns `.FALSE.` for `PENDING=`, or a `WAIT` statement has been executed; in each case, for that file.

#### 9.7.15.2 Basic Example

The following example uses two buffers, `buf1` and `buf2`, alternately reading into one while processing the other, while there is still data in the file to process (each dataset being followed by a single logical value which indicates whether more is to come).

      REAL :: buf1(n,m),buf2(n,m)
      LOGICAL more,stillwaiting
      READ (unit) buf1
      DO
        READ (unit) more ! Note: synchronous
        IF (more) READ (unit,ASYNCHRONOUS='YES') buf2
        CALL process(buf1)
        IF (.NOT.more) EXIT
        READ (unit) more ! Note: synchronous
        IF (more) READ (unit,ASYNCHRONOUS='YES') buf1
        CALL process(buf2)
        IF (.NOT.more) EXIT
      END DO

Note that the synchronous `READ` statements automatically “wait” for any outstanding asynchronous data transfer to complete before reading the logical value; this ensures that the dataset will have finished being read into its buffer and is safe to process.

#### 9.7.15.3 The `ASYNCHRONOUS` attribute [5.2]

A `READ` or `WRITE` statement with `ASYNCHRONOUS='YES'` automatically gives the `ASYNCHRONOUS` attribute to any variable that appears in its input/output list, in a `SIZE=` specifier, or which is part of a namelist specified by `NML=`. This is adequate for asynchronous data transfers that initiate and complete within a single procedure. However, it is inadequate for transfers to/from module variables or dummy arguments if the procedure returns while the transfer is still underway.

The `ASYNCHRONOUS` attribute may be explicitly specified in a type declaration statement or in an `ASYNCHRONOUS` statement. The latter has the syntax

`ASYNCHRONOUS` [`::`] variable-name [ `,` variable-name ]...

If a variable with the `ASYNCHRONOUS` attribute is a dummy array and is not an assumed-shape array or array pointer, any associated actual argument cannot be an array section, an assumed-shape array or array pointer. Furthermore, if a dummy argument has the `ASYNCHRONOUS` attribute the procedure must have an explicit interface. Both of these restrictions apply whether the attribute was given explicitly or implicitly.

#### 9.7.15.4 The `WAIT` statement [5.2]

The `WAIT` statement provides the ability to wait for an asynchronous data transfer to finish without performing any other input/output operation. It has the form

`WAIT` ( wait-spec [ `,` wait-spec ]... )

where wait-spec is one of the following:

`UNIT =` file-unit-number
`END =` label
`EOR =` label
`ERR =` label
`ID =` scalar-integer-variable
`IOMSG =` scalar-default-character-variable
`IOSTAT =` scalar-integer-variable

The `UNIT=` specifier must appear, but the ‘`UNIT =`’ may be omitted if it is the first specifier in the list. The `ID=` specifier takes a scalar integer expression whose value must be that returned from `ID=` on a `READ` or `WRITE` statement for the file; if the `ID=` specifier does not appear the `WAIT` statement refers to all pending asynchronous data transfer for that file.

On completion of execution of the `WAIT` statement the specified asynchronous data transfers have been completed. If the specified file is not open for asynchronous input/output or is not connected, the `WAIT` statement has no effect (it is not an error unless the `ID=` specifier was used with an invalid value).

Here is an example of using the `WAIT` statement.

      REAL array(1000,1000,10),xferid(10)
      ! Start reading each segment of the array
      DO i=1,10
        READ (unit,id=xfer(i)) array(:,:,i)
      END DO
      ...
      ! Now process each segment of the array
      DO i=1,10
        WAIT (unit,id=xfer(i))
        CALL process(array(:,:,i)
      END DO

#### 9.7.15.5 Execution Semantics

At this time all actual input/output operations remain synchronous, as allowed by the standard.

### 9.7.16 Scale factor followed by repeat count [5.1]

The comma that was previously required between a scale factor (n`P`) and a repeat count (e.g. the ‘`3`’ in `3E12.2`), is now optional. This trivial extension was part of Fortran 66 that was removed in Fortran 77, and reinstated in Fortran 2003.

### 9.7.17 FLUSH statement [5.2]

Execution of a `FLUSH` statement causes the data written to a specified file to be made available to other processes, or causes data placed in that file by another process to become available to the program. The syntax of the `FLUSH` statement is similar to the `BACKSPACE`, `ENDFILE` and `REWIND` statements, being one of the two possibilities

`FLUSH` file-unit-number
`FLUSH (` flush-spec [ , flush-spec ]... `)`

where file-unit-number is the logical unit number (a scalar integer expression), and flush-spec is one of the following:

`UNIT =` file-unit-number
`IOSTAT =` scalar-integer-variable
`IOMSG =` scalar-default-character-variable
`ERR =` label

The `UNIT=` specifier must appear, but the ‘`UNIT =`’ may be omitted if it is the first flush-spec in the list.

Here is an example of the use of a `FLUSH` statement.

       WRITE (pipe) my_data
       FLUSH (pipe)

### 9.7.18 Defined input/output [6.2]

The generic identifiers `READ(FORMATTED)`, `READ(UNFORMATTED)`, `WRITE(FORMATTED)` and `WRITE(UNFORMATTED)` provide the ability to replace normal input/output processing for an item of derived type. In the case of formatted input/output, the replacement will occur for list-directed formatting, namelist formatting, and for an explicit format with the `DT` edit descriptor: it does not affect any other edit descriptors in an explicit format. Using defined input/output, it is possible to perform input/output on derived types containing pointer components and allocatable components, since the user-defined procedure will be handling it.

Here is a type definition with defined input/output procedures.

      TYPE tree
        TYPE(tree_node),POINTER :: first
      CONTAINS
        PROCEDURE :: fmtread=>tree_fmtread
        PROCEDURE :: fmtwrite=>tree_fmtwrite
        GENERIC,PUBLIC :: READ(formatted)=>fmtread, WRITE(formatted)=>fmtwrite
      END TYPE

Given the above type definition, whenever a `TYPE(tree)` object is an effective item in a formatted input/output list, the module procedure `tree_fmtread` will be called (in a `READ` statement) or the module procedure `tree_fmtwrite` will be called (in a `WRITE` statement) to perform the input or output of that object. Note that a generic interface block may also be used to declare procedures for defined input/output; this is the only option for sequence or `BIND(C)` types but is not recommended for extensible types.

The procedures associated with each input/output generic identifier must have the same characteristics as the ones listed below, where type-declaration is `CLASS(`derived-type-spec`)` for an extensible type and `TYPE(`derived-type-spec`)` for a sequence or `BIND(C)` type. Note that if the derived type has any length type parameters, they must be “assumed” (specified as ‘`*`’).

`SUBROUTINE formatted_read(var,unit,iotype,vlist,iostat,iomsg)`
type-declaration`,INTENT(INOUT) :: var`
`INTEGER,INTENT(IN) :: unit`
`CHARACTER(*),INTENT(IN) :: iotype`
`INTEGER,INTENT(IN) :: vlist(:)`
`INTEGER,INTENT(OUT) :: iostat`
`CHARACTER(*),INTENT(INOUT) :: iomsg`

`SUBROUTINE unformatted_read(var,unit,iostat,iomsg)`
type-declaration`,INTENT(INOUT) :: var`
`INTEGER,INTENT(IN) :: unit`
`INTEGER,INTENT(OUT) :: iostat`
`CHARACTER(*),INTENT(INOUT) :: iomsg`

`SUBROUTINE formatted_write(var,unit,iotype,vlist,iostat,iomsg)`
type-declaration`,INTENT(IN) :: var`
`INTEGER,INTENT(IN) :: unit`
`CHARACTER(*),INTENT(IN) :: iotype`
`INTEGER,INTENT(IN) :: vlist(:)`
`INTEGER,INTENT(OUT) :: iostat`
`CHARACTER(*),INTENT(INOUT) :: iomsg`

`SUBROUTINE unformatted_write(var,unit,iostat,iomsg)`
type-declaration`,INTENT(IN) :: var`
`INTEGER,INTENT(IN) :: unit`
`INTEGER,INTENT(OUT) :: iostat`
`CHARACTER(*),INTENT(INOUT) :: iomsg`

In each procedure, `unit` is either a normal unit number if the parent input/output statement used a normal unit number, a negative number if the parent input/output statement is for an internal file, or a processor-dependent number (which might be negative) for the ‘`*`’ unit. The `iostat` argument must be assigned a value before returning from the defined input/output procedure: either zero to indicate success, the negative number `IOSTAT_EOR` (from the intrinsic module `ISO_FORTRAN_ENV`) to signal an end-of-record condition, the negative number `IOSTAT_END` to signal an end-of-file condition, or a positive number to indicate an error condition. The `iomsg` argument must be left alone if no error occurred, and must be assigned an explanatory message if `iostat` is set to a nonzero value.

For the formatted input/output procedures, the `iotype` argument will be set to ‘`LISTDIRECTED`’ if list-directed formatting is being done, ‘`NAMELIST`’ if namelist formatting is being done, and ‘`DT`’ concatenated with the character-literal if the `DT` edit descriptor is being processed. The `vlist` argument contains the list of values in the `DT` edit descriptor if present, and is otherwise a zero-sized array. Note that the syntax of the `DT` edit descriptor is:

`DT` [ character-literal ] [ `(` value [ `,` value ]... `)` ]

where blanks are insignificant, character-literal is a default character literal constant with no kind parameter, and each value is an optionally signed integer literal constant with no kind parameter. For example, ‘DT’, ‘DT"z8,i4,e10.2"’, ‘DT(100,-3,+4,666)’ and ‘DT"silly example"(0)’ are all syntactically correct `DT` edit descriptors: it is up to the user-defined procedure to interpret what they might mean.

During execution of a defined input/output procedure, there must be no input/output for an external unit (other than for the `unit` argument), but input/output for internal files is permitted. No file positioning commands are permitted. For unformatted input/output, all input/output occurs within the current record, no matter how many separate data transfer statements are executed by the procedure; that is, file positioning both before and after “nested” data transfer is suppressed. For formatted input/output, this effect is approximately equivalent to the nested data transfer statements being considered to be nonadvancing; explicit record termination (using the slash (`/`) edit descriptor, or transmission of newline characters to a stream file) is effective, and record termination may be performed by a nested list-directed or namelist input/output statement.

If `unit` is associated with an external file (i.e. non-negative, or equal to one of the constants `ERROR_UNIT`, `INPUT_UNIT` or `OUTPUT_UNIT` from the intrinsic module `ISO_FORTRAN_ENV`), the current settings for the pad mode, sign mode, etc., can be discovered by using `INQUIRE` with `PAD=`, `SIGN=`, etc. on the `unit` argument. If `unit` is negative (associated with an internal file), `INQUIRE` will raise the error condition `IOSTAT_INQUIRE_INTERNAL_UNIT`.

Finally, defined input/output is not compatible with asynchronous input/output; all input/output statements involved with defined input/output must be synchronous.