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

时间:2018-07-17 12:53:07

标签: io fortran

我有一个包含逗号分隔数字的文本文件,如下所示:

757.76019287, 759.72045898, 760.97259521, 763.45477295, 765.99475098, 770.2713623

不知道此文件中有多少这些数字;它有所不同,但仅限于几百个数字。

目标是:

  1. 打开此文件(例如customwav.txt),找出此文件中存在多少个数字->将它们放入整数n中。

  2. 将这些数字的内存分配到数组中->我已经有子例程可以为我执行此操作。

  3. 将数字行读取到此分配的数组中。

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

3 个答案:

答案 0 :(得分:2)

假设您的文件只有一行,看来:

  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
    

答案 1 :(得分:1)

我处理未知文件的方法是先使用流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.

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

答案 2 :(得分:1)

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))

numbers重新分配给正确的大小。