"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
显然格式化数据没有问题,否则写入标准输出会失败。我能想到的是 CRLF
s ('/'
) 导致 write()
将结果呈现为数组而不是标量。将数组写入标准输出可以正常工作(每行一个条目),但如果它试图将数组写入标量,则会失败。
来自 gfortran
和 ifort
的错误消息还有很多不足之处;向已故的道格拉斯·亚当斯致歉:“大部分没用”
有什么想法吗?
更新: 继续分析,问题是我对 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_LINE
和 C_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!
在将格式化输出写入变量时,出现错误
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
显然格式化数据没有问题,否则写入标准输出会失败。我能想到的是 CRLF
s ('/'
) 导致 write()
将结果呈现为数组而不是标量。将数组写入标准输出可以正常工作(每行一个条目),但如果它试图将数组写入标量,则会失败。
来自 gfortran
和 ifort
的错误消息还有很多不足之处;向已故的道格拉斯·亚当斯致歉:“大部分没用”
有什么想法吗?
更新: 继续分析,问题是我对 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_LINE
和 C_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!