在 Fortran 90 中,按行将数组写入文本文件的好方法是什么? [英] In Fortran 90, what is a good way to write an array to a text file, row-wise?

查看:260
本文介绍了在 Fortran 90 中,按行将数组写入文本文件的好方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am new to Fortran, and I would like to be able to write a two-dimensional array to a text file, in a row-wise manner (spaces between columns, and each row on its own line). I have tried the following, and it seems to work in the following simple example:

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,等等.

As I said, this seems to work fine in this simple example: the resulting text file, aoutput.txt, contains the numbers 1-762 on line 1, numbers 763-1524 on line 2, and so on.

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

But, when I use the above ideas (i.e., the last fifth-to-last, fourth-to-last, third-to-last, and second-to-last lines of code above) in a more complicated program, I run into trouble; each row is delimited (by a new line) only intermittently, it seems. (I have not posted, and probably will not post, here my entire complicated program/script--because it is rather long.) The lack of consistent row delimiters in my complicated program/script probably suggests another bug in my code, not with the four-line write-to-file routine above, since the above simple example appears to work okay. Still, I am wondering, can you please help me think if there is a better row-wise write-to-text file routine that I should be using?

非常感谢您抽出宝贵时间.我真的很感激.

Thank you very much for your time. I really appreciate it.

推荐答案

这里有几个问题.

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

The fundamental one is that you shouldn't use text as a data format for sizable chunks of data. It's big and it's slow. Text output is good for something you're going to read yourself; you aren't going to sit down with a printout of 3.81 million integers and flip through them. As the code below demonstrates, the correct text output is about 10x slower, and 50% bigger, than the binary output. If you move to floating point values, there are precision loss issues with using ascii strings as a data interchange format. etc.

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

If your aim is to interchange data with matlab, it's fairly easy to write the data into a format matlab can read; you can use the matOpen/matPutVariable API from matlab, or just write it out as an HDF5 array that matlab can read. Or you can just write out the array in raw Fortran binary as below and have matlab read it.

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

If you must use ascii to write out huge arrays (which, as mentioned, is a bad and slow idea) then you're running into problems with default record lengths in list-drected IO. Best is to generate at runtime a format string which correctly describes your output, and safest on top of this for such large (~5000 character wide!) lines is to set the record length explicitly to something larger than what you'll be printing out so that the fortran IO library doesn't helpfully break up the lines for you.

在下面的代码中,

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

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

generates the string rowfmt which in this case would be (762(1X,I6)) which is the format you'll use for printing out, and the RECL option to OPEN sets the record length to be something bigger than 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

这篇关于在 Fortran 90 中,按行将数组写入文本文件的好方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆