简体   繁体   中英

Reading variable length data in FORTRAN

I have an input file that I cannot alter the format. One of the lines in particular can contain either 6 or 7 reals and I don't have any way of knowing ahead of time.

After some reading, my understanding of the list-formatted read statement is that if I attempt to read 7 reals on a line containing 6, it will attempt to read from the next line. The author of the code says that when it was written, it would read the 6 reals and then default the 7th to 0. I am assuming he relied on some compiler specific behavior, because I cannot find a mention of this behavior anywhere.

I am using gfortran as my compiler, is there a way to specify this behavior? Or is there a good way to count a number of inputs on a line and rewind to then chose to read the correct number?

here is a little trick to accomplish that

 character*100 line
 real array(7)
 read(unit,'(a)')line  !read whole line as string'
 line=trim(line)//' 0' !add a zero to the string
 read(line,*)array  !list read

If the input line only had 6 values, the zero is now the seventh. If there were seven to begin with it will do nothing.

I try to avoid using format specifiers on input as much as possible.

Maybe you should use the IOSTAT statement for detecting the wrong format when you attempt to read 7 values when there are only 6. And you should use the ADVANCE statement to be able to retry to read the same line.

READ(LU,'7(F10.3)', IOSTAT=iError, ADVANCE='NO') MyArray(1:7)
IF(iError > 0) THEN
    ! Error when trying to read 7 values => try to read 6 !
    READ(LU, '6(F10.3)') MyArray(1:6)
ELSEIF(iError == 0) THEN
    READ(LU, *) ! For skipping the line read with success with 7 values
ENDIF

IOSTAT takes a negative value for example when you reach the end of the file, positive for problem of reading (typically formatting error) and 0 when the read succeed. See this link for a complete definition of gfortran error code: http://www.hep.manchester.ac.uk/u/samt/misc/gfortran_errors.html

Another way to do it could be to read the line as a string and manipulating the string in order to get the vector values :

CHARACTER(LEN=1000) :: sLine
...
READ(LU, '(A)') sLine
READ(sLine,'7(F10.3)', IOSTAT=iError) MyArray(1:7)
IF(iError > 0) THEN
    ! Error when trying to read 7 values => try to read 6 !
    READ(sLine, '6(F10.3)') MyArray(1:6)
ENDIF

If the values are written in fixed format, you can determine the lenght of the vector by testing the lenght of the line:

CHARACTER(LEN=1000) :: sLine
INTEGER :: nbValues
CHARACTER(LEN=2) :: sNbValues
...
READ(LU, '(A)') sLine
nbValues = LEN_TRIM(sLine) / 10 ! If format is like '(F10.x)'
WRITE(sNbValues, '(I2)') nbValues
READ(sLine, '('//TRIM(sNbValues)//'(F10.3))') MyArray(1:nbValues)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM