File io 如何在Fortran中读取可能包含很长行的文本文件

File io 如何在Fortran中读取可能包含很长行的文本文件,file-io,fortran,File Io,Fortran,例如,假设我有一个文本文件,其中可能包含很长的文本行 short short reeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaally loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooonnnnggg short as well short 我可以编写一个简单的程序来读取此文件: program main impli

例如,假设我有一个文本文件,其中可能包含很长的文本行

short
short
reeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaally loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooonnnnggg
short as well
short
我可以编写一个简单的程序来读取此文件:

program main
implicit none
integer, parameter        :: BIG_NUMBER = 400
integer                   :: lun
character(len=BIG_NUMBER) :: line
integer                   :: istat

open(newunit = lun, file = 'myfile')

do
   read (lun, '(A)', iostat = istat) line
   if (istat /= 0) exit
end do

end program main
这仅支持文本文件,其中所有行的长度不超过400个字符。在C语言中,使用指针,类似的程序会自动支持任何文本文件


如何重写示例程序,使其能够读取所有长度的行?

如果手头有另一个解决方案,请不要寻求另一个解决方案,除非它有一些限制。因为你可以用C语言来完成,而且C和Fortran之间的互操作性都很好,所以我建议你用C语言编写一小部分程序来处理阅读。 C部分可以简单为一组2个函数和几个全局变量:

  • 一个查询下一行大小的函数,除EOF标志外,该函数实际读取下一行并将其大小返回给fortran
  • 获取下一行数据的函数,该函数将行数据返回到fortran

  • 例如,如果使用的是
    getline
    ,则全局变量将是文件对象、行缓冲区和缓冲区大小。此外,您可以添加另外两个由fortran调用的函数来打开和关闭文件,也可以在查询函数中处理所有这些操作。

    您可以使用非前进输入将行的连续块读取到缓冲区中,然后将每个块组合在一起,形成延迟长度字符变量中的完整行。例如:

    subroutine get_line(lun, line, iostat, iomsg)
      integer, intent(in)           :: lun
      character(len=:), intent(out), allocatable :: line
      integer, intent(out)          :: iostat
      character(*), intent(inout)   :: iomsg
    
      integer, parameter            :: buffer_len = 80
      character(len=buffer_len)     :: buffer
      integer                       :: size_read
    
      line = ''
      do
        read ( lun, '(A)',  &
            iostat = iostat,  &
            iomsg = iomsg,  &
            advance = 'no',  &
            size = size_read ) buffer
        if (is_iostat_eor(iostat)) then
          line = line // buffer(:size_read)
          iostat = 0
          exit
        else if (iostat == 0) then
          line = line // buffer
        else
          exit
        end if
      end do
    end subroutine get_line
    

    您可以使用格式化流访问,读取一个字符接一个字符,并将它们放入堆栈或队列中。当遇到行结束字符时,请分配一个适当的长字符变量并复制堆栈内容。另请参阅。请注意:不要介意语法突出显示,
    /
    不是注释的开始,而是字符串连接。我们是否使用隐式重新分配
    ,但是对于延迟长度可分配字符变量,默认情况下,所有具有重要F2008功能的编译器都支持此功能。这是一个非常好的子例程,但是如果您对非常长的行的效率感兴趣,您至少应该将缓冲区变大很多,例如4k。甚至更好的方法是,在每次迭代中增加一个乘法因子来增加缓冲区的大小,以使重新分配+复制的成本达到对数。但这可能是不必要的复杂性,除非你真的需要它。。