Fortran 使用非前进I/O从文件中读取和计数(双精度)实数:使用什么编辑描述符?

Fortran 使用非前进I/O从文件中读取和计数(双精度)实数:使用什么编辑描述符?,fortran,Fortran,我试图从外部文件中将实数列表读入数组。我不知道一个文件中每个记录有多少记录字段(以空格分隔),因此我计划使用非前进I/O来首先计算记录字段的数量,然后分配一个足够大的实际数组,最后将文件读入同一数组 下面是一个示例输入文件(其中,每个记录字段的编辑描述符应为f3.1,即一个3个字符宽的浮点,带一个小数点,并计算点;但如果我正确读取Metcalf等人的数据,则忽略小数点): 我的程序的MWE看起来像这样 program testread use iso_fortran_env i

我试图从外部文件中将实数列表读入数组。我不知道一个文件中每个记录有多少记录字段(以空格分隔),因此我计划使用非前进I/O来首先计算记录字段的数量,然后分配一个足够大的实际数组,最后将文件读入同一数组

下面是一个示例输入文件(其中,每个记录字段的编辑描述符应为
f3.1
,即一个3个字符宽的浮点,带一个小数点,并计算点;但如果我正确读取Metcalf等人的数据,则忽略小数点):

我的程序的MWE看起来像这样

program testread
    use iso_fortran_env

    implicit none

    character(len=255) :: filename

    filename = 'read.dat'

    print *, count_entries(filename)

    contains
        integer function count_entries(coefficient_file) result(n)
            character(len=*), intent(in) :: coefficient_file
            !real, dimension(:), allocatable :: coefficients

            integer :: fileunit, stat
            real :: temp

            n=0

            open(newunit=fileunit, file=coefficient_file, iostat=stat)
                do
                    read(fileunit,'(f3.1)',advance='no',iostat=stat) temp
                    if (stat == iostat_end) then
                        exit
                    else
                        n = n + 1
                    end if
                    print *, stat, temp
                end do
            close(fileunit)

            ! What should happen in the future...
            !allocate(coefficients(n))
            !read(fileunit,*,iostat=stat) coefficients
        end function count_entries

end program testread
如果将上面的示例输入保存为
read.dat
,使用
gfortran-o testread{.f90}
编译程序并执行它,您将得到以下结果:

   0   1.00000000    
   0   2.00000000    
   0  0.300000012    
   0   0.00000000    
   0   4.00000000    
   0   5.00000000    
  -2   0.00000000    
   7
换句话说,它不计算5个条目,而是计算7个条目。这并不奇怪,因为出于某种原因,它看到了7个数字。但我想知道:为什么它会看到7个数字?如何将我的函数扩展到a)也能够读取较大的实数和b)读取非均匀宽度的实数?例如,我希望能够读取
1.01 1.003 2.1
,等等。

它看到六个数字(最后一个是记录结束条件),因为您的格式规范指定每次读取三个字符,但您的数据每四列间隔一次(三个用于数据,一个用于分隔空白)

如果输入的格式不固定(列数可能不同),则将整个记录(行)读入可分配的
字符(:),然后手动切碎该字符串


(除非您知道您的输入将始终适合于指定小数位数的格式规范,否则切勿使用具有指定小数位数的格式规范进行输入。)

您忘了考虑空格。只需使用
'(f3.1,1x)

不幸的是,您显然调用了与Fortran标准中的含义不同的record。通常在文本文件中,一条记录是一行;我编辑了我的问题部分,其中我指的是空格分隔的字段,但写的是“记录”。在Freenode上的##fortran中,有人向我指出certik的fortran utils,其中包含的过程
loadtxt
完全按照您的建议进行。因此我最终使用了:@mSSM
loadtxt
的实际实现实际上非常不同,但这是一个很好的选择。@VladimirF我在考虑如何按照IanH的建议实现它。但是,正如他所说,在我的脑海中,“切碎绳子”也需要沿着绳子走,并决定下一个空间何时到来,对吗?还是有更优雅的方式?
   0   1.00000000    
   0   2.00000000    
   0  0.300000012    
   0   0.00000000    
   0   4.00000000    
   0   5.00000000    
  -2   0.00000000    
   7