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

查看:20
本文介绍了在 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天全站免登陆