简体   繁体   English

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

[英]Reading a line containing comma-separated floats from file using Fortran

I have a text file containing comma-separated numbers like so: 我有一个包含逗号分隔数字的文本文件,如下所示:

757.76019287, 759.72045898, 760.97259521, 763.45477295, 765.99475098, 770.2713623

It is not known how many of these numbers are present in this file; 目前尚不知道此文件中有多少这些数字。 it varies but is limited to a few hundred numbers. 它有所不同,但仅限于几百个数字。

The objective is to: 目的是:

  1. Open this file (say, customwav.txt ) and find out how many numbers are present in this file --> put them into an integer n . 打开此文件(例如customwav.txt ),找出此文件中存在多少个数字->将它们放入整数n

  2. Allocate memory for these numbers into an array --> I already have subroutines that do this for me. 将这些数字的内存分配到数组中->我已经有子例程可以为我执行此操作。

  3. Read the line of numbers into this allocated array. 将数字行读取到此分配的数组中。

What is the best way to do 1 and 3 in Fortran? 在Fortran中执行1和3的最佳方法是什么?

Assuming your file only has one line, as it seems: 假设您的文件只有一行,如下所示:

  1. If you know the format of the numbers, you can do non-advancing I/O; 如果您知道数字的格式,则可以执行非高级I / O;否则,可以执行高级I / O。 eg, if all numbers are floats which use 12 spaces, of which 8 are decimal places, and they are separated by a comma followed by a space, without a final comma & space after the last number: 例如,如果所有数字都是浮点数,它们使用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. If you don't know the format, or the format changes in non-regular ways, a lazy (and inefficient) method would be to try to read the whole array at one time. 如果您不知道格式,或者格式以非常规方式更改,那么一种惰性(效率低下)的方法是尝试一次读取整个数组。 The following dumb code tries this by increasing the size one by one, but you could do bisection. 下面的哑代码尝试通过将大小一一增加来尝试此操作,但是您可以进行二等分。

     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. If non-Fortran tools are allowed, you can count the number of commas in the (single-line) file with the following shell command 如果允许使用非Fortran工具,则可以使用以下shell命令计算(单行)文件中的逗号数

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

    so the number of floats is that number possibly plus one (depending on the format). 因此浮点数是该数字可能加一(取决于格式)。 For multi-line files, you can obtain the list of counts of commas per line with 对于多行文件,您可以使用以下命令获取每行逗号计数的列表:

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

My approach for an unknown file is to first open it using stream I/O, read 1 character at a time and count the occurrence of all characters in the file : count_characters(0:255). 我处理未知文件的方法是先使用流I / O打开它,一次读取1个字符,然后计算文件中所有字符的出现:count_characters(0:255)。

This can tell you a lot about what to expect, such as: 这可以告诉您很多期望,例如:

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.

The advantage of this approach is that it identifies possible unusual data to be recovered. 这种方法的优点是它可以识别可能要恢复的异常数据。 It is probably best as a stand alone utility, as the interpretation can be difficult to code. 最好将它作为独立的实用程序,因为解释可能很难编写。

OP tells us the file contains a few hundred real numbers, neatly separated by commas. OP告诉我们该文件包含数百个实数,并用逗号整齐地分隔。 Here's a simple approach to reading those into an array of the right size. 这是将它们读入适当大小的数组的一种简单方法。 This is indifferent to the number of lines in the file. 这与文件中的行数无关。

First, declare an allocatable array, and an integer for handling the end of file which will occur later 首先,声明一个可分配的数组,以及一个用于处理文件结尾的整数,该整数将在以后出现

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

... allocate the array, with some overhead. ...分配数组,但会产生一些开销。 Yes, I'm just going to read however many numbers are in the file in one gulp, I'm not going to try to figure out how many there are. 是的,我将一口气读取文件中的许多数字,而我不会尝试找出有多少数字。

allocate(numbers(1000))

... set every value to a guard value whose utility will be obvious later; ...将每个值都设置为保护值,其实用性稍后会变得很明显; this does assume that the file won't contain the chosen guard value 这确实假定该文件将不包含所选的保护值

numbers  = -huge(1.0)

... read the numbers; ...阅读数字; I assume the file is already open on unit inunit 我认为该文件已经在unit inunit打开

read(inunit,*,iostat=ios) numbers

... at this point ios has a non-zero value but for the simple case outlined in the question there's no need to do anything with it, we've been told that there are only a few hundred of them. ...此时ios值非零,但对于问题中概述的简单情况,无需对其进行任何处理,我们被告知只有数百个。 And finally 最后

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

to reallocate numbers to the right size. numbers重新分配到正确的大小。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM