"too many records in I/O statement" 错误的原因不明

Unclear cause of "too many records in I/O statement" error

在将格式化输出写入变量时,出现错误

forrtl: severe (27): too many records in I/O statement

我已经检查了明显的事情 - 数据是否超过格式长度,反之亦然,变量的数量和类型与格式说明符兼容 - 我不明白为什么会抛出错误。

一个最小的说明性示例是:

program TXTERR27
    use iso_fortran_env, only: OUTPUT_UNIT    
    implicit none

    double precision :: F1, F2
    integer :: I1
    character (len=25), parameter :: A1 = 'AaaaaAaaaaAaaaaAaaaaAaaaa'

    character (len=250) :: A2

10  format(/, 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', I3, 'ZZZZZZZZZZZ',     &
    F10.3, 1X, A25, /, 'ZZZZZZZZZZZZZZZZZ', F6.3, 'ZZZZZZZZ')
20  format('Result :[', A250, ']')

    continue

    I1 = 1
    F1 = 1.0D0
    F2 = 1.0D-3

    write(OUTPUT_UNIT, *) "This works:"
    write(OUTPUT_UNIT, 10) I1, F1, A1, F2
    write(OUTPUT_UNIT, *)

    write(OUTPUT_UNIT, *) "This doesn't:"
    write(A2, 10) I1, F1, A1, F2
    write(OUTPUT_UNIT, 20) A2

    stop
end program TXTERR27

这是使用以下方法编译的:

ifort -warn all -check all -traceback -o txterr27 txterr27.f90

并且没有警告或错误结果。输出结果如下:

 This works:

ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ  1ZZZZZZZZZZZ     1.000 AaaaaAaaaaAaaaaAaaaaAaaaa
ZZZZZZZZZZZZZZZZZ 0.001ZZZZZZZZ

 This doesn't:
forrtl: severe (27): too many records in I/O statement, unit -5, file Internal Formatted Write
Image              PC                Routine            Line        Source             
txterr27           000000000046EEBE  Unknown               Unknown  Unknown
txterr27           000000000046D956  Unknown               Unknown  Unknown
txterr27           00000000004266A2  Unknown               Unknown  Unknown
txterr27           0000000000403BBB  Unknown               Unknown  Unknown
txterr27           0000000000403122  Unknown               Unknown  Unknown
txterr27           0000000000419A44  Unknown               Unknown  Unknown
txterr27           0000000000417BFC  Unknown               Unknown  Unknown
txterr27           0000000000402586  MAIN__                     26  txterr27.f90
txterr27           00000000004021DC  Unknown               Unknown  Unknown
libc.so.6          00007F083D474EC5  Unknown               Unknown  Unknown
txterr27           00000000004020D9  Unknown               Unknown  Unknown

为了检查这是否是特定于编译器的问题,我在 gfortran 下重建了示例代码:

gfortran -pedantic -Wall -fbacktrace -o txterr27 txterr27.f90                                                               

得到了相似的结果:

 This works:

ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ  1ZZZZZZZZZZZ     1.000 AaaaaAaaaaAaaaaAaaaaAaaaa
ZZZZZZZZZZZZZZZZZ 0.001ZZZZZZZZ

 This doesn't:
At line 26 of file txterr27.f90
Fortran runtime error: End of file

显然格式化数据没有问题,否则写入标准输出会失败。我能想到的是 CRLFs ('/') 导致 write() 将结果呈现为数组而不是标量。将数组写入标准输出可以正常工作(每行一个条目),但如果它试图将数组写入标量,则会失败。

来自 gfortranifort 的错误消息还有很多不足之处;向已故的道格拉斯·亚当斯致歉:“大部分没用

有什么想法吗?

更新: 继续分析,问题是我对 Fortran 中 'record' 的理解。这是更新后的插图:

program TXTERR27A
    use iso_fortran_env, only: OUTPUT_UNIT    
    implicit none

    double precision :: F1, F2
    integer :: I1
    character (len=25), parameter :: A1 = 'AaaaaAaaaaAaaaaAaaaaAaaaa'

    character (len=250) :: A2
    character (len=250), dimension(5) :: A3

10  format(/, 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ', I3, 'ZZZZZZZZZZZ',     &
    F10.3, 1X, A25, /, 'ZZZZZZZZZZZZZZZZZ', F6.3, 'ZZZZZZZZ')
20  format('Result: [', A250, ']')
30  format('Result:', /, '[', *(A250, ']', /, '['))

    continue

    I1 = 1
    F1 = 1.0D0
    F2 = 1.0D-3
    A2 = ''
    A3 = ''

    write(OUTPUT_UNIT, *) "This works:"
    write(OUTPUT_UNIT, 10) I1, F1, A1, F2
    write(OUTPUT_UNIT, *)

    write(OUTPUT_UNIT, *) "Does this?"
    write(A3, 10) I1, F1, A1, F2
    write(OUTPUT_UNIT, 30) A3

    write(OUTPUT_UNIT, *) "This doesn't:"
    write(A2, 10) I1, F1, A1, F2
    write(OUTPUT_UNIT, 20) A2

    stop
end program TXTERR27A

此示例显示在写入内部变量时发出多个 records/strings 并且问题(正如所怀疑的那样)是 write() 试图将数组放入标量。如果您将 '/' 视为记录分隔符,而不是简单的 CRLF:

,这是有道理的
 This works:

ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ  1ZZZZZZZZZZZ     1.000 AaaaaAaaaaAaaaaAaaaaAaaaa
ZZZZZZZZZZZZZZZZZ 0.001ZZZZZZZZ

 Does this?
Result:
[                                                                                                                                                                                                                                                          ]
[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ  1ZZZZZZZZZZZ     1.000 AaaaaAaaaaAaaaaAaaaaAaaaa                                                                                                                                                                         ]
[ZZZZZZZZZZZZZZZZZ 0.001ZZZZZZZZ                                                                                                                                                                                                                           ]
[                                                                                                                                                                                                                                                          ]
[                                                                                                                                                                                                                                                          ]
[
 This doesn't:
At line 34 of file txterr27.f90
Fortran runtime error: End of file

如果您牢记 Fortran I/O 古老的面向记录的特性,这个问题就很明显了。在长期使用带有文本 I/O 设施的语言后,这一点很容易忘记,比如 1969 年之后开发的。很抱歉没有直接看到这一点。

无论如何,重要的是要记住 '/' 是一个记录分隔符,而不是将其视为 Fortran 版本的 \n

新行说明符 / 用作列表定向输入的分隔符。因此,您正试图将三个记录写入一个内部文件。

内部文件只允许一个,所以在第一条记录之后,到达内部文件的末尾。也就是说,gfortran 告诉你的是什么。

斜线编辑描述符(/)不直接标记新行(CRLF,或任何适合系统的内容)。它仅表示传输到(在输出的情况下)当前记录的结束。当您的处理器将记录视为一行时,您会在输出到标准输出时看到此清单作为新行。

内部文件(字符变量)不同。在您有标量字符变量 (A2) 的地方,它定义了变量长度的单个记录。当您尝试向此变量写入多个记录时,您会看到错误。

但是,可以将多个记录写入内部文件,正如我们在 Fortran 2008 9.4 中看到的那样:

If the file is a character array, it is treated as a sequence of character array elements. Each array element, if any, is a record of the file.

然后,您可以将 A2 声明为大小(至少)3 的数组。

或者,如果您确实在将标量变量中的新行作为单个记录之后,您可以考虑 new_line 固有的,或者命名常量 C_NEW_LINEC_CARRIAGE_RETURN内部模块 iso_c_binding.

我之前遇到过非常相似的问题...当我试图在数据文件中查找标签时 </DATA> 喜欢

<DATA>
100 200 300
</DATA>

使用像

这样的程序
program main
    character(50) :: str
    open( 10, file="some.xml", status="old" )
    do
        read( 10, * ) str
        print *, trim( str )
        if ( str == "</DATA>" ) then
            print *, "tag found!"
            exit
        endif
    enddo
    close(10)
end

我遇到了一个错误

 <DATA>
 100
 <
At line 7 of file test.f90 (unit = 10, file = 'some.xml')
Fortran runtime error: End of file

并且花了很长时间才注意到 Fortran 不喜欢斜杠 (/)...通过将读取语句更改为

read( 10, "(a)" ) str

程序给出了预期的结果

<DATA>
100 200 300
</DATA>
tag found!