按列写入数组到文件

时间:2014-05-23 16:22:37

标签: arrays file io fortran90

有没有办法逐列将列写入文件?例如,我想写:

 write(1,*) 1
 write(1,*) 2

然后写(可能在另一个子程序中)

 write(1,*) 3
 write(1,*) 4

以这种方式生成格式为

的输出文件
 1   3
 2   4

没有组合数组(例如)

 write(1,*) 1,3
 write(1,*) 2,4

我认为可能有一种方法可以移动"指针" (文件位置)回到开头并添加空格或东西,但我真的不知道这是否可行。非常感谢任何帮助!

到目前为止,这是我尝试制作一个子程序来完成这项工作:

  subroutine writeArrayToNthColumn(arr,u,n)
    implicit none
    real(dpn),dimension(:),intent(in),target :: arr
    real(dpn),dimension(:),pointer :: parr
    integer,intent(in) :: u,n
    integer :: i,s
    s = size(arr)
    allocate(parr(s))
    parr = arr
    rewind(u)
    if (n.eq.1) then
      do i=1,s
        write(u,'(1F20.10)') parr(i)
      enddo
    else
      do i=1,s
        write(u,'(1F40.10)') parr(i)
      enddo
    endif
  end subroutine

但是第二次调用子程序时,第一列被删除了。

2 个答案:

答案 0 :(得分:2)

以上乔治和高绩效标志的评论是完全正确的。我发布这个作为答案,因为它有源代码,但它应该被视为扩展注释,其唯一目的是证明它们是正确的。

从某种意义上说,可以执行此操作,但在任何情况下都不应该这样做。在文件中移动 - 所谓的seek - 是一项非常昂贵的操作。在本地硬盘驱动器上,每次操作可能需要10-20毫秒左右(例如,在这种情况下,每个条目);如果你使用的是大型共享系统,那么它可能会大得多。

然而,在内存中移动物品要便宜得多。经过良好调整的transpose函数将在缓存中进行大部分移动,操作需要几纳秒;数据将以较少的操作进入和从主存储器进行批量处理,每次操作大约需要100ns左右。即使是对现代SSD的追求也需要几十微秒的时间。

换句话说,在文件I / O中进行转置的情况不会比在内存中进行转置 数百倍。 (如果需要,然后回来)。你仍然必须在最后做文件/ IO,但是如果你在一批中写出来,这要快得多。

让我们在Fortran中尝试一些例子,因为这是这个问题的语言。理所当然,Fortran使得难以直接访问文件位置,甚至在回车中显式输出,这使得这更难一些。我在这里使用direct-access IO并以非便携的方式硬编码进行回车。

这是在你的I / O中进行转置:

program badiotxt

    implicit none
    integer, parameter :: asize = 200
    integer, dimension(asize, asize) :: a
    integer :: i, j
    integer :: record

    forall (i=1:asize, j=1:asize)
        a(i,j) = (i-1)*asize+j
    end forall

    open(unit=7,file="bad.txt", status="new", access="direct", &
         form="formatted", action="write", recl=10)

    do j=1,asize
        do i=1,asize-1
            record=(j-1)*asize+i
            write(7, rec=record, fmt="(2X,I7,1X)") a(i,j)
        enddo
    enddo
    i = asize
    do j=1,asize
        record=(j-1)*asize+i
        write(7, rec=record, fmt="(1X,I7,A1,A1)") a(i,j), char(13), char(10)
    enddo

    close(7)

end program badiotxt

这是通过转置数组完成的:

program goodiotxt

    implicit none
    integer, parameter :: asize = 200
    integer, dimension(asize, asize) :: a
    integer :: i, j
    integer :: record

    forall (i=1:asize, j=1:asize)
        a(i,j) = (i-1)*asize+j
    end forall

    open(unit=7,file="good.txt", status="new",  &
         form="formatted", action="write")

    a = transpose(a)

    do i=1,asize
        write(7,fmt="(1X,200(2X,I7))") (a(i,j), j=1,asize)
    enddo

    a = transpose(a)

    close(7)

end program goodiotxt

请注意,好的版本是更干净的代码,并且这些不是任何延伸的大型数组。由此产生的时间是:

  • 内存转置:0.05s
  • 在磁盘上转置:1.70s
  • 减速:34x

答案 1 :(得分:2)

我现在比我第一次评论这个问题的时间多一点。然而,这是一个扩展的评论,而不是一个完整的答案。

即使是IF(这是一个很大的问题)我必须逐列编写一个数据文件,我不会使用直接访问IO,因为@Jonathan Dursi的答案提议。 (直接访问IO)适用于在编写代码时难以预测写入文件的顺序的情况。在OP的情况下,写入的顺序似乎完全可以预测。

我会:

  1. 将第1列(逐个元素)写入文件。
  2. 2.1打开第二个文件写入,第一个文件用于阅读。

    2.2从第一个文件中读取第一行,将其写入第二个文件并附加下一列的第一个元素。

    2.3重复2.2直到我到达列/文件的末尾。

    2.4关闭第二个文件(现在包含第1列和第2列)和第一个文件。

    3.1打开第二个文件进行阅读,并对第一个文件执行破坏性打开以进行写入。

    ......到现在为止你应该得到了照片。