If Fortran90 + means you are happy with Fortran 2003, then there is an option for a user-defined derived type of IO. This allows you to wrap an additional account, necessary for placement in the record. I will put an example code below.
If you do not want to use this function, perhaps because you do not have a compiler that supports it (I tested with ifort 14), then you can easily simulate accounting.
The most important part is simply sending and reading sizes and allocating variables before reading.
The code:
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
Of course, much needs to be done to make it reliable.