【问题标题】:Reading a line containing comma-separated floats from file using Fortran使用 Fortran 从文件中读取包含逗号分隔的浮点数的行
【发布时间】:2018-07-17 12:53:06
【问题描述】:

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

757.76019287, 759.72045898, 760.97259521, 763.45477295, 765.99475098, 770.2713623

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

目标是:

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

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

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

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

【问题讨论】:

  • 到目前为止您尝试了什么,请添加一个 MWE(最小工作示例)。这种类型的问题(一行上的可变数量的值)已经在这个网站上提出过,请搜索,我想你会找到一些东西。您要解决的问题不仅仅是 Forran90 问题,而是一般 Fortran 问题,对于更广泛的受众,请使用标签 Fortran
  • 如果您正在生成输入文件,请考虑添加要读取的值的总数,作为数据的第一个值。
  • 看来您需要的是一个 CSV 文件阅读器。如果是这样,看看这个Fortran CSV package
  • 您需要对某些假设进行限制,例如:行的长度是否有限制。如果有并且有多行,则进行第一遍计算行数,每行中的逗号数和一行中的最大逗号。(num_commas + num_lines = num_values)。然后倒带,分配数组并读取数据。或者,您知道文件大小,因此请保守猜测。给定可用内存,您通常可以大致了解所需的内容;一百万行和一千万个值涵盖了很多可能性,如果你有 8gb 内存,这将是非常少的。

标签: io fortran


【解决方案1】:

假设您的文件似乎只有一行:

  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
    

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      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重新分配到正确的大小。

      【讨论】:

      • 这种方法的问题是假设值是数字,因为无论是在错误还是超出它们都取决于处理器。我有不同的 Fortran 编译器,它们返回不同的结果。对于“read (line,*,iostat=iostat) (aa(i),i=1,k)”,一个编译器 FTN95 返回 I= 发生错误的值(这很有帮助),而另一个 gFortran 返回 I=k+1 (不是)。 gFortran 也会在发生错误的地方返回值 0,但 FTN95 没有定义该值。错误响应未定义是个问题。另一个问题是能够将读取限制为文件的 1 行/记录。
      猜你喜欢
      • 2011-09-22
      • 2021-06-16
      • 2015-03-19
      • 2014-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-21
      • 1970-01-01
      相关资源
      最近更新 更多