阅读免费格式,无需提前

时间:2014-01-16 18:31:56

标签: file-io io fortran

在给定的文件记录中,我需要先读取前两个整数元素,然后读取其余部分(大量真实元素),因为赋值取决于前两个。假设格式为前两个整数元素没有很好地定义。

解决问题的最佳方法可能是:

read(unitfile, "(I0,I0)", advance='no') ii, jj
read(unitfile,*) aa(ii,jj,:)

但在我看来,gfortran中不允许使用“(I0)”规范。

基本上,在unitfile中读取的文件可能类似于:

0   0    <floats>
0   10   <floats>
10   0    <floats>
100   0    <floats>
100   100    <floats>

很难用任何类似Fortran的固定字段格式规范来阅读。

有没有其他方法可以解决这个问题,显然是微不足道的问题?

2 个答案:

答案 0 :(得分:3)

这会使用字符串操作来获取单个组件,由空格' '和/或制表符(char(9))分隔:

program test
  implicit none
  character(len=256) :: string, substring
  integer            :: ii, jj, unitfile, stat, posBT(2), pos
  real, allocatable  :: a(:)

  open(file='in.txt', newunit=unitfile, status='old' )
  read(unitfile,'(a)') string

  ! Crop whitespaces
  string = adjustl(trim(string))

  ! Get first part:
  posBT(1) = index(string,' ')      ! Blank
  posBT(2) = index(string,char(9))  ! Tab
  pos = minval( posBT, posBT > 0 )

  substring = string(1:pos)
  string = adjustl(string(pos+1:))
  read(substring,*) ii

  ! Get second part:
  posBT(1) = index(string,' ')      ! Blank
  posBT(2) = index(string,char(9))  ! Tab
  pos = minval( posBT, posBT > 0 )

  substring = string(1:pos)
  string = adjustl(string(pos+1:))
  read(substring,*) jj

  ! Do stuff
  allocate( a(ii+jj), stat=stat )
  if (stat/=0) stop 'Cannot allocate memory'

  read(string,*) a

  print *,a

  ! Clean-up
  close(unitfile)
  deallocate(a)
end program

对于文件in.txt,例如:

1 2 3.0 4.0 5.0

这导致

./a.out 
   3.00000000       4.00000000       5.00000000

注意:这只是一个快速而简单的示例,可根据您的需要进行调整。

答案 1 :(得分:3)

[这个答案已经过重大修改:原件不安全。感谢IanH指出这一点。]

当我能负担得起时,我通常会尽量避免执行非列表导向的格式化输入。已经有一个字符串解析的答案非常普遍,但我会提供一些简单设置的建议。

当您放心地信任输入时,例如当它只是格式化时有点棘手(或者您很乐意将它留给编译器的边界检查),您可以使用

来处理您的示例案例
read(unitfile, *) ii, jj, aa(ii, jj, :)

或者,如果数组部分比前两列直接给出的更复杂,则可以通过表达式,甚至是函数

read(unitfile, *) ii, jj, aa(fi(ii,jj), fj(ii,jj), :fn(ii,jj))

使用pure integer function fi(ii,jj)等。甚至有可能在这些函数中进行范围验证(例如,返回0大小的部分)。

在更一般的情况下,但保持列表导向,可以使用缓冲区作为实际变量

read(unitfile, *) ii, jj, buffer(:) ! Or ... buffer(:fn(ii,jj))
! Validate ii and jj before attempting to access aa with them
aa(.., .., :) = buffer

其中缓冲区的大小合适。

您首先考虑的方法表明您对线的结构有一些合理的了解,包括长度,但是当iijj或类型(和不允许多态性读取)不知道,那么事情确实变得棘手。此外,如果一个人对验证输入非常敏感,或者甚至提供有意义的详细用户错误反馈,那么这不是最佳的。

最后,iostat有帮助。