【问题标题】:Reading data file in Fortran with known number of lines but unknown number of entries in each line在 Fortran 中读取行数已知但每行条目数未知的数据文件
【发布时间】:2011-11-10 23:15:09
【问题描述】:

如何读取包含已知行数但每行中的条目数未知的数据文件,例如如果我的数据文件包含类似

1 3 4 5 6 -7 8 -9

1 3 5 6

4 5 6 7 8 3 5 6 7 8 4 5 7 8

即三行,但每行中的数据是未知的。有一次我需要来自一行的数据。

【问题讨论】:

    标签: fortran


    【解决方案1】:

    基于 M. S. B. 指出的实现。很晚了,但我想它可能对某人有用。

    准备好您希望读取的类型的数组:

    double precision, dimension(MAX_NUM_OF_COLS) :: test_array
    

    从文件中读取一行:

    READ(reading_unit,'(A)',iostat=io) line
    

    循环并尝试从该行中读取最大数量的数字:

    do i=1,MAX_NUM_OF_COLS
      READ(line, *, iostat=io) test_array(1:i)
      if(io==0) exit
    enddo
    
    write(*,*) 'number of columns = ', (i-1)
    

    如果需要,循环遍历文件的所有行,并保持最大或最小列数。

    最小示例:

    integer, parameter :: MAX_NUM_OF_COLS=30
    integer, parameter :: MAX_LINE_LENGTH=1000
    character(len=MAX_LINE_LENGTH) line
    integer i, io, reading_unit
    double precision, dimension(MAX_NUM_OF_COLS) :: test_array
    
    reading_unit=100
    OPEN(reading_unit, file='the_file')
    
    ! Get first line of file.
    DO
      READ(reading_unit,'(A)',iostat=io) line
      IF (io/=0) then
        write(*,*) "Error reading file."
        stop
      endif
      exit ! Eventually, do not exit and put the DO loop below here.
    ENDDO
    CLOSE(reading_unit)
    
    do i=1,MAX_NUM_OF_COLS
      READ(line,*,iostat=io) test_array(1:i)
      if(io==-1) exit
    enddo
    
    write(*,*) 'number of columns = ', (i-1)
    

    【讨论】:

      【解决方案2】:

      假设您可以用零填充数组(具体参考后面的重复问题here),这是我的想法:

      将数据逐行读取成一个字符串,然后附加多个零,最后从这个数组中读取每一行数据。这是一个例子:

      program unknown_numbers
      
          implicit none
          integer, parameter :: nrow=3, ncol=14
          integer :: data(ncol, nrow)
          character(len=2*ncol) :: zeros ! will contain lots of zeros
          character(len=10*ncol) :: line ! temporary storage for each line of the file
          integer :: i, u
      
          ! Write " 0 0 0 0 0 0 0 0" into the string "zeros"
          write(zeros, '(*(I2))') [(0, i=1, ncol)]
      
          open(newunit=u, file='data.txt', status='old', action='read')
      
          do i = 1, nrow, 1
              ! Read the next line into a temporary string array
              read(u, '(A)') line
              ! Append a number of zeros to the temporary string
              line = trim(line) // zeros
              ! Read the row of data from the string.
              read(line, *) data(:, i)
          end do
      
          close(u)
      
          ! For testing purposes, print the data.
          print '(14(X, I3))', data
      
      end program unknown_numbers
      

      【讨论】:

      • 非常漂亮。这里唯一的缺点是您不知道文件或填充中是否有实际的零。
      • 你是对的。我是从more recent question 来到这里的,其中用零填充是所需的行为,但它被声明为这个问题的重复。
      【解决方案3】:

      这是一个程序,可以计算一行(或列数)中的数字,但只计算一行。如果你有很多行,你应该稍微改变一下。

      program test12
      
      implicit none
      
      integer n,m,i
      
      integer,allocatable::x(:)
      
       open(10,file='C:\Users\user\Desktop\file.txt')
      
      allocate(x(n))
      
      20 n=n+1
      
       deallocate(x) 
      
      
      
       allocate(x(n))
      
      read(10,*,iostat=m)(x(i),i=1,n)
      
      if (m==-1)then
      
      goto 30
      
      else
      
      
      rewind 10
      
       goto 20
      
      end if
      
       30 print*,n-1
      
       end
      

      【讨论】:

      • 这是一个可以计算一行(或列数)数字的程序,但是对于一行。如果你有很多行,你应该稍微改变一下
      • 欢迎,尝试始终正确格式化您的帖子,并评论您在程序中使用的行的作用以及为什么它们是正确的解决方案。此外,您应该在代码中使用一致的缩进,并避免使用太多的 goto。许多人认为 Goto 是有害的。
      • 你真的应该考虑一个问题是否在 6 年前有一个公认的答案,你贡献了什么?
      【解决方案4】:
      integer,parameter :: reclen=99999        ! maximum record length
      integer,parameter :: undef=-9999         ! undefined value
      integer :: actual_reclen                 ! actual record length
      integer,dimension(reclen) :: dummy=undef ! dummy array used for reading
      integer,dimension(:),allocatable :: a    ! final array
      
      open(unit=10,file='sample.txt',form='formatted',access='sequential')
      read(unit=10,fmt=*,end=101)(dummy(i),i=1,reclen)
      101 close(unit=10)
      
      actual_reclen=COUNT(dummy/=undef)
      allocate(a(actual_reclen))
      a=dummy(1:actual_reclen)
      
      end
      

      【讨论】:

      • 非常感谢您的回复,这将读取文件中的所有数据,而不是逐行读取。我使用了 MSB 建议的方法,效果很好
      【解决方案5】:

      一种方法:将行读入字符串,使用至少与最长预期行一样长的字符串。然后你开始解析字符串。例如,如果数字总是用空格分隔,则使用它来确定子字符串的边界。然后您可以使用“内部读取”从每个子字符串中读取以获取数值。内部读取使用字符串而不是单位编号并从字符串中获取数据——至少您不必重新创建字符到数值的转换,读取语句会为您完成。 Fortran 提供的内在函数将使解析更容易。

      【讨论】:

        猜你喜欢
        • 2021-09-14
        • 2017-10-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-22
        相关资源
        最近更新 更多