arrays - 在 Fortran 90 中,按行将数组写入文本文件的好方法是什么?

标签 arrays fortran text-files

我是 Fortran 的新手,我希望能够以行方式将二维数组写入文本文件(列之间的空间,每一行都在自己的行上)。我尝试了以下方法,它似乎适用于以下简单示例:

PROGRAM test3
  IMPLICIT NONE

  INTEGER :: i, j, k, numrows, numcols
  INTEGER, DIMENSION(:,:), ALLOCATABLE :: a

  numrows=5001
  numcols=762
  ALLOCATE(a(numrows,numcols))
  k=1
  DO i=1,SIZE(a,1)
    DO j=1,SIZE(a,2)
      a(i,j)=k
      k=k+1
    END DO
  END DO

  OPEN(UNIT=12, FILE="aoutput.txt", ACTION="write", STATUS="replace")
  DO i=1,numrows
    WRITE(12,*) (a(i,j), j=1,numcols)
  END DO
END PROGRAM test3

正如我所说,这在这个简单的例子中似乎工作正常:生成的文本文件, aoutput.txt , 包含第 1 行的数字 1-762、第 2 行的数字 763-1524,依此类推。

但是,当我在一个更复杂的程序中使用上述想法(即,上面的倒数第五行、倒数第四行、倒数第三行和倒数第二行代码)时,我运行陷入麻烦;似乎每行只是间歇性地(由新行)分隔。 (我没有发布,也可能不会发布,这里我整个复杂的程序/脚本——因为它很长。)我的复杂程序/脚本中缺乏一致的行分隔符可能表明我的代码中存在另一个错误,而不是上面的四行写入文件例程,因为上面的简单示例似乎工作正常。不过,我想知道,你能帮我想想是否有更好的逐行写入文本文件例程我应该使用吗?

非常感谢您的宝贵时间。对此,我真的非常感激。

最佳答案

这里有几个问题。

最基本的一点是你不应该使用文本作为大量数据的数据格式。它很大而且很慢。文本输出适合您自己阅读的内容;你不会坐下来打印 381 万个整数并翻阅它们。正如下面的代码所示,正确的文本输出比二进制输出慢 10 倍,大 50%。如果您转向浮点值,则使用 ascii 字符串作为数据交换格式存在精度损失问题。等等。

如果您的目标是与 matlab 交换数据,那么将数据写入 matlab 可以读取的格式是相当容易的;您可以使用 matlab 中的 matOpen/matPutVariable API,或者只是将其写为 matlab 可以读取的 HDF5 数组。或者你可以像下面这样用原始 Fortran 二进制写出数组,然后得到 matlab read it .

如果您必须使用 ascii 来写出巨大的数组(如前所述,这是一个糟糕且缓慢的想法),那么您将遇到列表导向 IO 中默认记录长度的问题。最好是在运行时生成一个正确描述输出的格式字符串,对于如此大的(~5000 个字符宽!)行,最安全的是将记录长度显式设置为大于您将要打印的长度这样 fortran IO 库就不会帮助您拆分行。

在下面的代码中,

  WRITE(rowfmt,'(A,I4,A)') '(',numcols,'(1X,I6))'

生成字符串 rowfmt,在本例中为 (762(1X,I6))这是您将用于打印的格式,以及 RECL选项 OPEN将记录长度设置为大于 7*numcols + 1。
PROGRAM test3
  IMPLICIT NONE

  INTEGER :: i, j, k, numrows, numcols
  INTEGER, DIMENSION(:,:), ALLOCATABLE :: a
  CHARACTER(LEN=30) :: rowfmt
  INTEGER :: txtclock, binclock
  REAL    :: txttime, bintime

  numrows=5001
  numcols=762
  ALLOCATE(a(numrows,numcols))
  k=1
  DO i=1,SIZE(a,1)
    DO j=1,SIZE(a,2)
      a(i,j)=k
      k=k+1
    END DO
  END DO

  CALL tick(txtclock)
  WRITE(rowfmt,'(A,I4,A)') '(',numcols,'(1X,I6))'
  OPEN(UNIT=12, FILE="aoutput.txt", ACTION="write", STATUS="replace", &
       RECL=(7*numcols+10))
  DO i=1,numrows
    WRITE(12,FMT=rowfmt) (a(i,j), j=1,numcols)
  END DO
  CLOSE(UNIT=12)
  txttime = tock(txtclock)

  CALL tick(binclock)
  OPEN(UNIT=13, FILE="boutput.dat", ACTION="write", STATUS="replace", &
       FORM="unformatted")
  WRITE(13) a
  CLOSE(UNIT=13)
  bintime = tock(binclock)

  PRINT *, 'ASCII  time = ', txttime
  PRINT *, 'Binary time = ', bintime

CONTAINS

    SUBROUTINE tick(t)
        INTEGER, INTENT(OUT) :: t

        CALL system_clock(t)
    END SUBROUTINE tick

    ! returns time in seconds from now to time described by t
    REAL FUNCTION tock(t)
        INTEGER, INTENT(IN) :: t
        INTEGER :: now, clock_rate

        call system_clock(now,clock_rate)

        tock = real(now - t)/real(clock_rate)
    END FUNCTION tock
END PROGRAM test3

关于arrays - 在 Fortran 90 中,按行将数组写入文本文件的好方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6526112/

相关文章:

javascript - 使用高阶函数在数组中查找数组的索引?

php - 按最高值对 n 个项目进行多维自定义排序

fortran - 使用lapack的dgemm(链接器错误)

fortran - "Hello World!"示例来自哪里?

java - 以相反的顺序将数组 A 中的所有 N 个整数打印为单行空格分隔的整数

C# 数组索引总是超出

module - Makefile:避免为新文件夹编译 Fortran 模块

Java从带有撇号和连字符的文件中读取单词并将它们计为2个单词

string - 替换文本文件中一行的值

c - 打印到 C 中的文件