Fortran90+ 中具有可分配组件的数据类型的二进制读/写 [英] Binary Read/Write of Data Types with Allocatable Components in Fortran90+
问题描述
保存由以下 sample
数据类型组成的变量 save
的二进制快照的最佳方法是什么?
What is the best way to save a binary snapshot of the variable save
which is made out of sample
data type below?
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+ 中做到这一点.
There is pretty straight binary input/output streaming in C++ but I don't know how to do it in Fortran 90+.
推荐答案
如果说 Fortran90+ 意味着你对 Fortran 2003 很满意,那么可以选择用户定义的派生类型 IO.这允许您将分配所需的额外簿记包装在 write 语句中.我会把示例代码放在底部.
If by Fortran90+ you mean you are happy with Fortran 2003, then there is the option of user-defined derived type IO. This allows you to wrap the extra bookkeeping required for the allocation in the write statement. I'll put example code at the bottom.
如果您不想使用此功能,可能是因为您没有支持它的编译器(我已经使用 ifort 14 进行了测试),那么您可以很容易地模仿簿记.
If you don't want to use this feature, which is possibly because you don't have a compiler which supports it (I've tested with ifort 14), then you can mimic the bookkeeping easily enough.
关键部分只是发送和读取大小并在读取之前分配变量.
The crucial part is just sending out and reading back in the sizes and allocating the variables before the read.
代码:
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
要让它变得健壮,肯定还有很多工作要做.
There's certainly a lot of work to be done on making it robust.
这篇关于Fortran90+ 中具有可分配组件的数据类型的二进制读/写的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!