从未知大小的文件中读取数组

时间:2015-11-24 16:40:39

标签: arrays fortran fortran90

我不是Fortran 90的新手,但我很好奇是否存在我问题的简单解决方案。我有一个看起来像这样的文件:

.git/info/exclude

其中1 2 3 ... n 可以是任何整数,我想将文件中的每个数字读成整数数组n。换句话说,A。在运行代码之前,我不知道n有多大。我的解决方案是打开文件,从中读取所有内容,找到n,然后A=(1,2,3,...,n),然后重新读取文件:

allocate A(n)

但是,为了优雅,可以避免这种双重阅读吗?

2 个答案:

答案 0 :(得分:2)

以下是一个非常简单的链表示例:

module list_mod
implicit none
  type list_int
    integer                 :: val = 0
    integer                 :: length = 0
    type(list_int), pointer :: next => NULL()
    type(list_int), pointer :: tail => NULL()
  end type
contains
  subroutine append( list, val )
    type(list_int), intent(inout) :: list
    integer                       :: val

    if ( associated(list%next) ) then
      allocate( list%tail%next )
      list%tail => list%tail%next
    else
      allocate( list%next )
      list%tail => list%next
    endif
    list%tail%val = val
    list%length = list%length + 1
  end subroutine
end module

您可以使用它来按条目读入文件条目。列表的长度随着每个项目的增加而增加。此信息用于分配一个数组,然后以文件为单位。

program test
  use list_mod
  implicit none
  type(list_int)          :: ilist
  type(list_int), pointer :: cur
  integer,allocatable     :: array(:)
  integer                 :: i, io

  open( unit=20, file="test.txt", status='old' )
  do
    read(unit=20,fmt=*,iostat=io) i
    if (io/=0) exit
    call append(ilist, i)
  enddo 

  allocate( array( ilist%length ) )
  cur => ilist%next
  i = 1
  do while (associated(cur))
    array( i ) = cur%val
    i = i + 1
    cur => cur%next
  enddo

  print *,array
end program

答案 1 :(得分:1)

我已经通过@VladimirF(在评论中)翻译了这个建议,如下所示。虽然vector_t的定义相当冗长(在自动扩展大小时可能与vector有些类似),但调用程序变得有点短。

module vector_mod
    implicit none

    type vector_t
        integer, allocatable :: elem(:)  !! elements
        integer              :: n        !! current vector size (<= size(elem))
    contains
        procedure :: push
        procedure :: resize
        procedure :: fit
    end type

contains

    subroutine push ( v, x )
        class(vector_t) :: v
        integer         :: x

        if ( allocated( v% elem ) ) then
            if ( v% n == size( v% elem ) ) call v% resize( v% n * 2 )
            v% n = v% n + 1
            v% elem( v% n ) = x
        else
            allocate( v% elem( 1 ) )
            v% n = 1
            v% elem( 1 ) = x
        endif
    end subroutine

    subroutine resize ( v, n )
        class(vector_t) :: v
        integer         :: n
        integer, allocatable :: buf(:)
        integer :: m

        allocate( buf( n ), source=0 )
        m = min( n, size(v% elem) )
        buf( 1:m ) = v% elem( 1:m )

        deallocate( v% elem )
        call move_alloc ( buf, v% elem )
    end subroutine

    subroutine fit ( v )
        class(vector_t) :: v
        call v% resize( v% n )
    end subroutine
end

program main
    use vector_mod, only: vector_t
    implicit none
    type(vector_t) :: v
    integer x, ios

    open( 10, file="test.dat", status="old" )
    do
        read( 10, *, iostat=ios ) x
        if ( ios /= 0 ) exit
        call v% push( x )
    enddo
    close( 10 )

    call v% fit()
    print *, v% elem(:)
end

但恕我直言,我想问题中给出的解决方案(即打开文件,从中读取所有内容,找到n,然后分配A(n)然后重新读取文件)将是最简单的... < / p>