简体   繁体   English

在FORTRAN中读取可变长度数据

[英]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. 特别是其中一行可以包含6或7个实数,而我没有任何提前知道的方法。

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. 经过一番阅读之后,我对列表格式的read语句的理解是,如果我尝试在包含6的行中读取7个实数,它将尝试从下一行进行读取。 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. 该代码的作者说,编写该代码时,它将读取6个实数,然后将第7个默认值设置为0。我假设他依赖于某些编译器特定的行为,因为在任何地方都找不到该行为的提及。

I am using gfortran as my compiler, is there a way to specify this behavior? 我使用gfortran作为编译器,是否可以指定这种行为? 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. 如果输入行只有6个值,则零现在是第七个。 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. 当尝试读取只有7个值的7个值时,也许应该使用IOSTAT语句检测错误的格式。并且应该使用ADVANCE语句重试读取同一行。

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. 例如,当您到达文件末尾时,IOSTAT取负值;对于读取问题(通常为格式错误),取值为IOSTAT;对于读取成功而言,取值为0。 See this link for a complete definition of gfortran error code: http://www.hep.manchester.ac.uk/u/samt/misc/gfortran_errors.html 有关gfortran错误代码的完整定义,请参见此链接: 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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