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 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:

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 (nP) 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.