【问题标题】:Using do loop in a Fortran 90 program to read different number of lines for n frames?在 Fortran 90 程序中使用 do 循环读取 n 帧的不同行数?
【发布时间】:2013-11-11 20:29:24
【问题描述】:

有一个文件有 1000 帧。每帧包含不同数量的行。每行有两列整数。但是,我不知道每帧包含多少行。每一帧都由一个空行分隔。我想读取这些值并将它们存储在一个数组中。但是,我无法分配数组大小,因为我不知道每帧有多少行。所以,我有两个问题:

  • 如何使用“do”循环来读取 fortran90 程序中的不同行数?我无法使用“计数控制执行”循环,因为我不知道每帧中的确切行数。
  • 如果我不能更早地分配数组的大小,如何将数字存储在数组中? 该文件如下所示:
1   2  
2   1

3   2

2   8   
4   5  
4   17  
2   10

等等……

有什么建议吗?

【问题讨论】:

  • 可以一次完成,但两次更容易。您是否需要为每一帧使用不​​同的阵列?你试过什么?
  • @VladimirF,不,我不需要为每一帧设置不同的数组。我需要使用相同的数组。对于每一帧,我都使用了一个开放的 do 循环,然后对我读取的每一行使用 count=count + 1。退出 do 循环后,我使用该计数值来分配数组大小并将值再次读入分配的数组。但是,它给出了一个运行时错误,说明文件结束。
  • 你应该在你的问题中向我们展示你的代码,然后避免这些不完整的描述。

标签: fortran fortran90


【解决方案1】:

最简单的方法是这样的(如有必要,颠倒行和列的索引顺序,并为我跳过的所有变量添加声明以保持简短)。它首先读取文件并确定行数。然后它倒带文件从头开始并读取已知行数。

  integer,allocatable :: a(:,:)
  integer :: pair(2)
  integer :: unit

  unit = 11
  
  open(unit,file="test.txt")
  n = 0
  do
    read(unit,*,iostat=io) pair
    if (io/=0) exit
    n = n + 1
  end do
  
  rewind(unit)

  allocate(a(n,2))
  
  do i=1,n
    read(unit,*) a(i,:)
  end do
  
  close(unit)
  
  print *, a
  
end

检查if (io/=0) exit 是通用的,将在遇到任何错误或记录/文件结束条件时触发。

Fortran 2003 包含 iso_fortran_env 模块中的特定常量,其中包含 iostat= 可以具有的特定值。

IOSTAT_END:
    The value assigned to the variable passed to the IOSTAT= specifier of an input/output statement if an end-of-file condition occurred.
IOSTAT_EOR:
    The value assigned to the variable passed to the IOSTAT= specifier of an input/output statement if an end-of-record condition occurred. 

因此,如果您只想检查文件结束条件,请使用

if (io/=iostat_end) exit

use 之前结束 iso_fortran_env 模块。


也可以完成一次通过的解决方案,使用临时数组可以轻松地增加数组(C++ 向量在后台执行相同的操作)。你甚至可以实现自己的成长类,但这超出了这个问题的范围。


如果您的数据有一个固定大小的长数组而不是一个可分配的数组,您可以跳过第一遍,只使用iostat= 说明符读取文件,并在它非零或等于@987654330 时完成读取@。

【讨论】:

    【解决方案2】:

    即使是现代版本的 Fortran (IMO) 的弱点之一是缺少扩展数组,例如 C++ 中的 std::vector 或 GLib/C 中的 GArray。是的,您可以自己编写这样的东西,但是缺少泛型/模板意味着您必须专门针对每种类型和种类,或者弄乱class(*) 和可分配的标量......呃。

    但我离题了。

    我可以看到两个选项。第一个是对文件进行两次遍历,首先计算每个空间之间的行数,并在执行过程中分配帧数组,然后第二次遍历实际用数据填充数组。

    第二种可能更“Fortran-y”的方法是拥有一个临时工作数组,该数组与您期望的单个帧一样大。用数据填充它,然后当你到达一帧的末尾时,分配一个大小合适的数组并将你刚刚读取的数据复制到其中。

    不幸的是,这两种解决方案都不是特别好。

    【讨论】:

    • 这并不难。向可分配数组添加一个元素就是array = [array, element]。它可能很慢,但通常你不在乎。看不到泛型或多态的混乱。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-29
    • 2012-09-03
    相关资源
    最近更新 更多