使用Fortran从文件中读取包含逗号分隔浮点值的行



我有一个文本文件,其中包含逗号分隔的数字,如:

757.76019287, 759.72045898, 760.97259521, 763.45477295, 765.99475098, 770.2713623

目前还不知道这个文件中有多少这样的数字;它各不相同,但仅限于几百个数字。

目标是:

  1. 打开这个文件(比如customwav.txt(,找出这个文件中有多少数字-->将它们放入一个整数n中。

  2. 将这些数字的内存分配到一个数组中-->我已经有了为我做这件事的子程序

  3. 将一行数字读入这个已分配的数组。

在Fortran中执行1和3的最佳方法是什么?

假设您的文件只有一行,如下所示:

  1. 如果你知道数字的格式,你可以进行非前进I/O;例如,如果所有数字都是使用12个空格的浮点数,其中8个是小数位数,并且它们由逗号和空格分隔,没有最后的逗号&最后一个数字后的空格:

    integer, parameter :: DP = selected_real_kind(15,300)
    real(kind=DP) :: x
    real(kind=DP), allocatable :: xall(:)
    integer :: u
    integer :: n
    character(len=2) :: c
    open(newunit=u, file='customwav.txt',status='old',action='read')
    n = 0
    do
    read(u, '(f12.8)', advance='no') x
    n = n + 1
    read(u, '(2a)', advance='no', eor=100) c
    if (c .ne. ', ') STOP 'unknown format'
    end do
    100 write(*,*) n
    allocate(xall(n))
    rewind(u)
    read(u, *) xall
    close(u)
    write(*,*) xall
    
  2. 如果您不知道格式,或者格式以非常规的方式更改,则一种懒惰(且效率低下(的方法是尝试一次读取整个数组。下面的愚蠢代码通过逐个增加大小来尝试这一点,但您可以进行平分。

    integer, parameter :: DP = selected_real_kind(15,300)
    integer, parameter :: MaxN = 1000
    real(kind=DP), dimension(MaxN) :: x
    integer :: u
    integer :: n
    integer :: error
    open(newunit=u, file='customwav.txt',status='old',action='read')
    error = 0
    n = 0
    do while (error.eq.0)
    read(u, *, iostat=error) x(1:n+1)
    if (error .eq. 0) then
    n = n + 1
    rewind(u)
    end if
    end do
    write(*,*) n
    rewind(u)
    read(u, *) x(1:n)
    close(u)
    write(*,*) x(1:n)
    
  3. 如果允许使用非Fortran工具,则可以使用以下shell命令计算(单行(文件中的逗号数

    $ grep -o ',' customwav.txt | wc -l
    

    所以浮点数可能是这个数字加一(取决于格式(。对于多行文件,您可以使用获得每行逗号计数的列表

    $ f=customwav.txt
    $ for lin in $(seq $(cat $f | wc -l))
    > do
    >   sed -n ${lin}'p' $f | grep -o ',' | wc -l
    > done
    

对于未知文件,我的方法是首先使用流I/O打开它,一次读取1个字符,并计算文件中所有字符的出现次数:count_characters(0:255(。

这可以告诉你很多关于预期的信息,例如:

LF indicates number of lines in file
CR indicates DOS file rather than unix file format
.  can indicate real numbers
,  can indicate csv file format
; / : can indicate other delimiters
presence of non-numeric characters indicates non-numeric information
E or e can indicate scientific format
/ or : can indicate date/time info
The count_<lf> + count_, is an estimate of numbers in the file.

这种方法的优点是,它可以识别可能要恢复的异常数据。作为一个独立的实用程序,它可能是最好的,因为解释可能很难编码。

OP>告诉我们该文件包含几百个实数,用逗号整齐地分隔。这里有一个简单的方法,可以将它们读取到合适大小的数组中。这与文件中的行数无关。

首先,声明一个可分配数组和一个整数,用于处理稍后发生的文件结尾

real, dimension(:), allocatable :: numbers
integer :: ios

分配数组,但需要一些开销。是的,我只是想一口气阅读文件中的数字,我不会试图弄清楚有多少。

allocate(numbers(1000))

将每个值设置为一个保护值,其效用稍后会很明显;这确实假设文件不会包含所选的保护值

numbers  = -huge(1.0)

读取数字;我认为inunit单元上的文件已经打开

read(inunit,*,iostat=ios) numbers

在这一点上,ios有一个非零值,但对于问题中概述的简单情况,没有必要对它做任何事情,我们被告知只有几百个。最后是

numbers = pack(numbers, numbers>-huge(1.0))

以将CCD_ 5重新分配到合适的大小。

最新更新