如何从一行中具有不同列的文件中读取数据
How to read data from a file with different column in a line
我想从一个文件中读取数据,其中每一行都有不同数量的数据,例如
a b c d
e f
h g k
我需要这样的格式 format(T8,<num>(I7))
其中 <num>
是在 运行 时间内确定的动态格式说明符,它指定了输入文件一行中的列数。
这是我要修改的代码。该代码在 Intel fortran 中有效,但在 gfortran 中出现错误。
do i=1,N
read(20,'(I7)') CV(i,1)
backspace(20)
15 format(T8,CV(i,1)(I7))
read(20,15) CV(i,2:CV(i,1)+1)
end do
错误信息是
15 format(T8,CV(i,1)(I7))
1
Error: Unexpected element ‘C’ in format string at (1)
您不需要可变格式来执行此操作。
处理输入列表时,处理输入项所需的任何值都在开始处理该项时确定。在这种情况下,可以使用一行的第一项来确定要读取的数组元素:
read(20, '(*(I7))') CV(i,1), CV(i,2:CV(i,1)+1)
格式的重复说明符("number of items to read"方面),在这种情况下,尝试使用CV(i,1)
的意思是什么,不需要匹配项目的数量:它只需要更大(在本例中 *
表示 "unlimited")。当列表中的所有项目都已读取时,处理停止。
这可以通过内部写入构造格式来完成,如下所示:
character(Len=30) :: form
do i=1,N
read(20,'(I7)') CV(i,1)
write( form, '(a,i0,a)' ) '(', CV(i,1), 'i7)'
backspace(20)
read(20,form) CV(i,2:CV(i,1)+1)
end do
为了避免 BACKSPACE,这真的很耗时,我通常更喜欢将输入读入字符行,然后我可以快速分析它。在您的特定情况下,由于输入数据的数量始终作为数据项 1 给出,@francescalus 给出的答案非常好。如果线条变化更大,您可以扩展以下代码(目前只是您的示例)
program read_data
!
integer, parameter :: MAX_DATA=10
integer, parameter :: MAX_ROWS=4
integer :: ios
integer :: i
character(len=18+7*MAX_DATA) :: line
integer, dimension(MAX_ROWS, MAX_DATA) :: cv
!
cv(:,:) = 0
open(unit=20, file='data.txt')
main_loop: do i=1, 4
read(20, '(a)', iostat=ios) line
if(is_iostat_end(ios)) exit main_loop
read(line(1:len_trim(line)),'(*(i2))', iostat=ios) cv(i,1), cv(i,2:cv(i,1)+1)
if(.not.(ios==0 .or. is_iostat_end(ios))) exit main_loop
write(*,*) i,cv(i,1), cv(i,1:6)
enddo main_loop
!
end program read_data
我想从一个文件中读取数据,其中每一行都有不同数量的数据,例如
a b c d
e f
h g k
我需要这样的格式 format(T8,<num>(I7))
其中 <num>
是在 运行 时间内确定的动态格式说明符,它指定了输入文件一行中的列数。
这是我要修改的代码。该代码在 Intel fortran 中有效,但在 gfortran 中出现错误。
do i=1,N
read(20,'(I7)') CV(i,1)
backspace(20)
15 format(T8,CV(i,1)(I7))
read(20,15) CV(i,2:CV(i,1)+1)
end do
错误信息是
15 format(T8,CV(i,1)(I7))
1
Error: Unexpected element ‘C’ in format string at (1)
您不需要可变格式来执行此操作。
处理输入列表时,处理输入项所需的任何值都在开始处理该项时确定。在这种情况下,可以使用一行的第一项来确定要读取的数组元素:
read(20, '(*(I7))') CV(i,1), CV(i,2:CV(i,1)+1)
格式的重复说明符("number of items to read"方面),在这种情况下,尝试使用CV(i,1)
的意思是什么,不需要匹配项目的数量:它只需要更大(在本例中 *
表示 "unlimited")。当列表中的所有项目都已读取时,处理停止。
这可以通过内部写入构造格式来完成,如下所示:
character(Len=30) :: form
do i=1,N
read(20,'(I7)') CV(i,1)
write( form, '(a,i0,a)' ) '(', CV(i,1), 'i7)'
backspace(20)
read(20,form) CV(i,2:CV(i,1)+1)
end do
为了避免 BACKSPACE,这真的很耗时,我通常更喜欢将输入读入字符行,然后我可以快速分析它。在您的特定情况下,由于输入数据的数量始终作为数据项 1 给出,@francescalus 给出的答案非常好。如果线条变化更大,您可以扩展以下代码(目前只是您的示例)
program read_data
!
integer, parameter :: MAX_DATA=10
integer, parameter :: MAX_ROWS=4
integer :: ios
integer :: i
character(len=18+7*MAX_DATA) :: line
integer, dimension(MAX_ROWS, MAX_DATA) :: cv
!
cv(:,:) = 0
open(unit=20, file='data.txt')
main_loop: do i=1, 4
read(20, '(a)', iostat=ios) line
if(is_iostat_end(ios)) exit main_loop
read(line(1:len_trim(line)),'(*(i2))', iostat=ios) cv(i,1), cv(i,2:cv(i,1)+1)
if(.not.(ios==0 .or. is_iostat_end(ios))) exit main_loop
write(*,*) i,cv(i,1), cv(i,1:6)
enddo main_loop
!
end program read_data