【问题标题】:Reading comment lines correctly in an input file using Fortran 90使用 Fortran 90 在输入文件中正确读取注释行
【发布时间】:2020-01-14 03:24:38
【问题描述】:

据我了解,Fortran 在从文件中读取数据时,会跳过以星号 (*) 开头的行,假设它们是注释。好吧,我似乎在用我创建的一个非常简单的程序实现这种行为时遇到了问题。这是我的简单 Fortran 程序:

  1       program test
  2 
  3       integer dat1
  4 
  5       open(unit=1,file="file.inp")
  6 
  7       read(1,*) dat1
  8 
  9 
 10       end program test

这是“file.inp”:

  1 *Hello
  2 1

我用

构建了我的简单程序
gfortran -g -o test test.f90

当我运行时,我得到了错误:

At line 7 of file test.f90 (unit = 1, file = 'file.inp')
Fortran runtime error: Bad integer for item 1 in list input

当我运行删除了注释行的输入文件时,即:

1 1

代码运行良好。因此,Fortran 正确解释该注释行似乎是一个问题。这一定是我在这里错过的非常简单的东西,但我无法在谷歌上找到任何东西。

【问题讨论】:

    标签: file-io comments fortran gfortran


    【解决方案1】:

    我发现使用backspace 语句比建议的解决方案更直观。当在行首遇到注释字符“#”时,以下子例程将跳过该行。

    subroutine skip_comments(fileUnit)
      integer, intent(in) :: fileUnit
      character(len=1) :: firstChar
    
      firstChar = '#'
      do while (firstChar .eq. '#')
        read(fileUnit, '(A)') firstChar
      enddo
      backspace(fileUnit)
    
    end subroutine skip_comments
    

    这个子程序可以用在read 语句之前的程序中,如下所示:

    open(unit=10, file=filename)
    call skip_comments(10)
    read(10, *) a, b, c
    call skip_comments(10)
    read(10, *) d, e
    close(10)
    

    上述实现的限制:

    1. 如果将注释放在 跨多行的变量的值(例如数组)的值之间,它将不起作用。
    2. 对于大型输入文件来说效率非常低,因为当遇到退格语句时,整个文件从头开始重新读取直到前一个字符。
    3. 只能用于sequential访问文件,即典型的ASCII文本文件。使用directappend 访问类型打开的文件将不起作用。

    但是,我发现它非常适合用于提供用户参数的短文件。

    【讨论】:

    • 我们不要忘记迷人的“禁止在使用列表导向或名单格式编写的记录上使用退格。”
    【解决方案2】:

    Fortran 不会自动跳过输入文件中的 cmets 行。您可以很容易地做到这一点,首先将行读入字符串,检查您的注释符号的第一个字符或在字符串中搜索该符号,然后如果该行不是注释,则对字符串进行“内部读取”以获取数值。

    类似:

    use, intrinsic :: iso_fortran_env
    
    character (len=200) :: line
    integer :: dat1, RetCode
    
    read_loop: do
       read (1, '(A)', isostat=RetCode)  line
        if ( RetCode == iostat_end)  exit ReadLoop
        if ( RetCode /= 0 ) then
          ... read error
          exit read_loop
        end if
        if ( index (line, "*") /= 0 )  cycle read_loop
        read (line, *) dat1
    end do read_loop
    

    【讨论】:

    • 是的,实际上我只是想通了,然后回来发布我的解决方案。但是,您的代码比我想出的解决方案要聪明一些(我在 read 语句中使用了“end =”选项)。不过,我不明白的一件事是使用“iso_fortran_env”有什么需要?抱歉,我已经编写了一些大型 Fortran 程序并让它们正常工作,但是对于内部模块以及它们带来的内容,我有点菜鸟。
    • 除其他外,iso_fortran_env 提供值“isostat_end”来测试非零返回码是否为文件结尾。这允许使用“exit”构造而不是语句标签,如“end=LineNumber”。
    【解决方案3】:

    默认情况下,Fortran 不会忽略任何内容,除非您使用名称列表并且在这种情况下 cmets 以感叹号开头。

    【讨论】:

      猜你喜欢
      • 2012-05-21
      • 2013-08-02
      • 2018-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-03
      • 1970-01-01
      相关资源
      最近更新 更多