Fortran90+中可分配组件的数据类型的二进制读/写

3

如何最好地保存下面的sample数据类型所组成的变量save的二进制快照呢?

program save_it

   type core
      integer, dimension(8) :: indx
   end type core 

   type sample
      integer :: a
      real*8, dimension(:), allocatable :: b
      type(core), dimension(:), allocatable :: c
   end type sample

   ! here it comes
   type(sample) :: save

   ! here we allocate all componenets of variable "save"
   !.
   !.

   ! Now, how to write/read variable "save" to/from external file?

end program save_it 

C++拥有非常直接的二进制输入/输出流,但我不知道如何在Fortran 90+中实现。

1个回答

3
如果你说的Fortran90+是指你满意Fortran 2003,那么可以选择用户定义派生类型IO选项。这允许你在写语句中包装所需的额外的簿记。我将在底部放置示例代码。
如果您不想使用此功能,可能是因为您没有支持它的编译器(我已经测试过ifort 14),那么您可以轻松地模拟簿记。
关键部分只是发送并再次读取大小并在读取之前分配变量。
代码:
module types

   type core
      integer, dimension(8) :: indx
   end type core 

   type sample
      integer :: a
      real*8, dimension(:), allocatable :: b
      type(core), dimension(:), allocatable :: c
    contains
      procedure write_sample
      procedure read_sample
      generic :: write(unformatted) => write_sample
      generic :: read(unformatted) => read_sample
   end type sample

   contains

     ! Unformatted writing for the sample derived type
     subroutine write_sample(dtv, unit, iostat, iomsg)
       class(sample), intent(in) :: dtv
       integer, intent(in) :: unit
       integer, intent(out) :: iostat
       character(*), intent(inout) :: iomsg

       integer i

       ! Write a record giving sizes for the allocation
       write(unit, iostat=iostat, iomsg=iomsg) SIZE(dtv%b), SIZE(dtv%c)
       write(unit, iostat=iostat, iomsg=iomsg) dtv%a, dtv%b, &
                                               (dtv%c(i)%indx, i=1,SIZE(dtv%c))

     end subroutine write_sample

     ! Unformatted reading for the sample derived type
     subroutine read_sample(dtv, unit, iostat, iomsg)
       class(sample), intent(inout) :: dtv
       integer, intent(in) :: unit
       integer, intent(out) :: iostat
       character(*), intent(inout) :: iomsg

       integer i
       integer sizeb, sizec

       ! We first have a record telling us the sizes of components
       read(unit, iostat=iostat, iomsg=iomsg) sizeb, sizec
       ! So we do the allocation
       allocate(dtv%b(sizeb), dtv%c(sizec))
       ! And then finally the reading.
       read(unit, iostat=iostat, iomsg=iomsg) dtv%a, dtv%b, &
                                             (dtv%c(i)%indx, i=1,SIZE(dtv%c))

     end subroutine read_sample

end module types

program save_it
   use types

   implicit none

   integer i, unit_in, unit_out

   ! here it comes
   type(sample) :: save
   type(sample) :: save_test

   ! Define some values - using ifort don't forget to set the compile flag
   save%a = 14
   save%b = [(i*1., i=1, 10)]
   save%c = [core([(i, i=1,8)]), core([(i, i=11, 18)])]

   ! Write out the derived type
   open(newunit=unit_out, file='serial', form='unformatted', &
        status='replace', action='write')
   write(unit_out) save
   close(unit_out)

   ! Read in the derived type to a new one
   open(newunit=unit_in, file='serial', form='unformatted', &
        status='old', action='read')
   read(unit_in) save_test
   close(unit_in)

   ! Test, if we want to be certain

end program save_it

肯定有很多工作要做,使其更加强大稳定。


非常有见地的代码和伟大的想法!谢谢。 - argasm
请注意,子输入/输出语句始终被视为非推进 - write_sample和read_sample过程仅在主程序中由父写入和读取语句创建的单个记录中编写和读取其数据。 - IanH
@IanH 非常好的观点,谢谢。也许在我的程序注释中,我应该用“块”而不是“记录”这个词?或者有一个更加中立/正确的术语? - francescalus
1
@francescalus 你在用哪个编译器?这个代码在gfortran 6.3.0上无法运行(我所知道的MinGW可用的最新版本)。我得到了以下错误信息:generic :: write(unformatted) => write_sample, Error: Expected '=>' at (1)。如果我删除(unformatted),我会得到以下错误信息:write(unit_out) save, Error: Data transfer element at (1) cannot have ALLOCATABLE components unless it is processed by a defined input/output procedure - Jeff Irwin
1
@JeffIrwin,我使用ifort(如果我的回答中的评论正确,则为14,未经过后续测试)。据我所知,您需要gfortran 7+才能支持定义的I/O。 - francescalus
@francescalus 谢谢!很抱歉我错过了你在回答中提到的ifort 14。不过,我找到了一个很好的解决方案来处理旧版本的gfortran格式化写入问题。我能够重载//运算符,然后将我的类型与其他要打印的字符连接起来。 - Jeff Irwin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接