【问题标题】:Fortran read() reads last line twice?Fortran read() 读取最后一行两次?
【发布时间】:2018-01-08 23:22:06
【问题描述】:

所以,假设我正在尝试读取一个我事先不知道其长度的文件。我们可以在需要时使用 iostat 和 while 循环来中断,但我对此有疑问。也就是说,我编写的代码读取了最后一行两次。我确信有一个明显的解决方案,但我似乎无法弄清楚。我不太了解 read() 或 iostat 函数是如何完全工作的(我对 fortran 很陌生),但我无法从文档中收集到太多信息,所以我希望这里有人能提供帮助。

这是我写的(相关的)代码:

filename = 'test.txt' 
iostat_1 = 0 
iostat_2 = 0 
open(newunit = lun, file = filename, status = 'old', iostat = iostat_1) 
if (iostat_1 == 0) then 
    do while(iostat_2 == 0)             
        if(iostat_2 == 0) then 
            read(lun,*,iostat = iostat_2) dum, real_1,real_2,int_1                   
            print *, dum, real_1,real_2,int_1                  
        endif
    enddo
endif

所以,假设我的输入文件是

1 1.0 1.0 1
2 2.0 2.0 1 
3 3.0 3.0 1
4 4.0 4.0 4 

那么从 print 语句到终端的输出将会是

1 1.0 1.0 1
2 2.0 2.0 1 
3 3.0 3.0 1
4 4.0 4.0 4 
4 4.0 4.0 4 

所以请记住以下几点:这里的主要目的是能够读取具有任意行数的文件。我对涉及首先读取行数的解决方案不感兴趣。

感谢您的帮助!

更新 好的,我刚刚解决了问题。话虽如此,我想知道是否有比我的更笨拙的解决方案。这是我为解决问题所做的工作

! Body of ReInsert
filename = 'rpriov3.dat' 
iostat_1 = 0 
iostat_2 = 0 
open(newunit = lun, file = filename, status = 'old', iostat = iostat_1) 
if (iostat_1 == 0) then 
    do while(iostat_2 == 0)             
        if(iostat_2 == 0) then 
            read(lun,*,iostat = iostat_2) dum, real_1,real_2,int_1   
            if(iostat_2 == 0) then !<---- Added this nested if statement
                print *, dum, real_1,real_2,int_1   
            endif                
            print *, iostat_2                 
        endif
    enddo
endif

【问题讨论】:

    标签: file-io fortran


    【解决方案1】:

    如您所见,当您设置 iostat 参数时,read 命令不会覆盖它要求的变量。

    正如您已经注意到的,您的解决方案有些复杂。

    首先:

    do while (condition)
        if (condition) then
            ...
        end if
    end do
    

    在这种情况下,内部if 语句是完全多余的。除非condition 为真,否则循环不会运行,因此除非condition 本身的评估不会改变结果1),否则if 子句将始终被执行。

    我要看的第二件事是:如果open 失败会发生什么?在大多数情况下,我想打印一个错误并退出:

    open(..., iostat=ios)
    
    if (ios /= 0) then
        print*, "Error opening file"
        STOP 1
    end if
    
    do while (...)
        ...
    end do
    

    即使您不想在open 出现错误的情况下退出程序,通常也有一些方法可以使代码比永久嵌套更具可读性。例如,您可以一次又一次地(在自己的循环中)向用户询问文件名,直到文件打开或用户输入一些退出消息。

    ios = 1
    do while (ios /= 0)
        write(*, *, advance='no') "Enter filename (or 'quit') :"
        read(*, *) filename
    
        if ( trim(filename) == "quit" ) STOP
    
        open(newunit=lun, file=filename, ..., iostat=ios)
    end do
    

    最后是最内部的if 块。由于您想在遇到错误时退出循环,因此您可以在循环内使用exit 语句立即退出循环,而无需执行循环块的其余部分:

    do
        read(..., iostat=ios) ...
        if (ios /= 0) exit
        print *, ....
    end do
    

    这是一个无限循环,一旦遇到读取错误(通常,但不一定是 EOF),就会带有显式 exit。由于print语句在exit之后,因此出现此类错误时不会执行。

    1) 我的意思是类似这样的 C sn-p i++ &lt; 10,这两个测试 i10 递增它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-05
      • 2014-12-21
      • 1970-01-01
      • 1970-01-01
      • 2011-11-26
      • 2011-05-18
      • 2012-12-04
      • 2014-12-01
      相关资源
      最近更新 更多