1

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

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

3   2

2   8   
4   5  
4   17  
2   10

等等...

有什么建议么?

4

2 回答 2

5

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

  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

结束之前useiso_fortran_env模块。


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


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

于 2013-11-01T08:36:23.527 回答
1

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

但我离题了。

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

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

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

于 2013-11-01T04:25:01.287 回答