Io Write语句无法在派生类型的用户定义的格式化I/O过程中生成新行

Io Write语句无法在派生类型的用户定义的格式化I/O过程中生成新行,io,fortran,newline,derived-types,formatted,Io,Fortran,Newline,Derived Types,Formatted,我想在Fortran代码中为派生类型实现用户定义的I/O过程。但是,这些过程中的write语句不能在两个连续的write语句之间生成新行。派生类型和过程定义如下 模块: module station_module implicit none character(8), parameter :: FmtFloat = '(5E15.7)' type :: station integer, private :: ns = 0 real, p

我想在Fortran代码中为派生类型实现用户定义的I/O过程。但是,这些过程中的
write
语句不能在两个连续的
write
语句之间生成新行。派生类型和过程定义如下

模块:

module station_module
    implicit none

    character(8), parameter :: FmtFloat = '(5E15.7)'

    type :: station
        integer, private :: ns = 0
        real, public, allocatable :: xloc(:), yloc(:), zloc(:)
    contains
        procedure, public :: import_station
        procedure, public :: export_station
        procedure, private :: read_station
        generic, public :: read (formatted) => read_station
        procedure, private :: write_station
        generic, public :: write (formatted) => write_station
        final :: destruct_station
    end type station

    interface station
        module procedure new_station
    end interface station

contains

    function new_station(n) result(t)
        implicit none
        integer, intent(in) :: n
        type(station) :: t

        if (n > 0) then
            allocate (t%zloc(n))
            allocate (t%yloc(n))
            allocate (t%xloc(n))
            t%ns = n
        end if
    end function new_station

    subroutine read_station(dtv, unit, iotype, vlist, iostat, iomsg)
        implicit none
        class(station), intent(inout) :: dtv
        integer, intent(in) :: unit
        character(*), intent(in) :: iotype
        integer, intent(in) :: vlist(:)
        integer, intent(out) :: iostat
        character(*), intent(inout) :: iomsg

        call dtv%import_station(unit)

        iostat = 0
    end subroutine read_station

    subroutine import_station(this, unit)
        implicit none
        class(station), intent(inout) :: this
        integer, intent(in) :: unit
        character(256) :: header, footer
        integer ns

        read (unit, '(A)') header !> Header
        read (unit, *) ns
        if (ns > 0) then
            if (allocated(this%zloc)) then
                deallocate (this%zloc)
            end if
            allocate (this%zloc(ns))
            read (unit, *) this%zloc

            if (allocated(this%yloc)) then
                deallocate (this%yloc)
            end if
            allocate (this%yloc(ns))
            read (unit, *) this%yloc

            if (allocated(this%xloc)) then
                deallocate (this%xloc)
            end if
            allocate (this%xloc(ns))
            read (unit, *) this%xloc

            this%ns = ns
        end if
        read (unit, '(A)') footer !> Footer
    end subroutine import_station

    subroutine export_station(this, unit)
        implicit none
        class(station), intent(in) :: this
        integer, intent(in) :: unit

        write (unit, '(A)') ">STATION INFO"
        write (unit, '(I6)') this%ns
        write (unit, *) "Z:"
        write (unit, FmtFloat) this%zloc
        write (unit, *) "Y:"
        write (unit, FmtFloat) this%yloc
        write (unit, *) "X:"
        write (unit, FmtFloat) this%xloc
        write (unit, '(A)') ">END STATION"
    end subroutine export_station

    subroutine write_station(dtv, unit, iotype, vlist, iostat, iomsg)
        implicit none
        class(station), intent(in) :: dtv
        integer, intent(in) :: unit
        character(*), intent(in) :: iotype
        integer, intent(in) :: vlist(:)
        integer, intent(out) :: iostat
        character(*), intent(inout) :: iomsg

        call dtv%export_station(unit)

        iostat = 0
    end subroutine write_station

    subroutine destruct_station(this)
        implicit none
        type(station), intent(inout) :: this

        if (allocated(this%xloc)) then
            deallocate (this%xloc)
        end if
        if (allocated(this%yloc)) then
            deallocate (this%yloc)
        end if
        if (allocated(this%zloc)) then
            deallocate (this%zloc)
        end if
        this%ns = 0
    end subroutine destruct_station

end module station_module
program Test
    use station_module
    implicit none
    type(station) :: pt, pt1, pt2

    pt = station(4)

    write(*, *) pt

    call pt%export_station(6)

end program Test
 >STATION INFO     4Z:  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
 Y:  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00X:  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00>END STATION
>STATION INFO
     4
 Z:
  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
 Y:
  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
 X:
  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
>END STATION
我们可以看到,用户定义的格式化的write语句只调用一个名为
export\u station
的常规子例程,我希望这两种方式的结果相同

这是我的测试程序:

module station_module
    implicit none

    character(8), parameter :: FmtFloat = '(5E15.7)'

    type :: station
        integer, private :: ns = 0
        real, public, allocatable :: xloc(:), yloc(:), zloc(:)
    contains
        procedure, public :: import_station
        procedure, public :: export_station
        procedure, private :: read_station
        generic, public :: read (formatted) => read_station
        procedure, private :: write_station
        generic, public :: write (formatted) => write_station
        final :: destruct_station
    end type station

    interface station
        module procedure new_station
    end interface station

contains

    function new_station(n) result(t)
        implicit none
        integer, intent(in) :: n
        type(station) :: t

        if (n > 0) then
            allocate (t%zloc(n))
            allocate (t%yloc(n))
            allocate (t%xloc(n))
            t%ns = n
        end if
    end function new_station

    subroutine read_station(dtv, unit, iotype, vlist, iostat, iomsg)
        implicit none
        class(station), intent(inout) :: dtv
        integer, intent(in) :: unit
        character(*), intent(in) :: iotype
        integer, intent(in) :: vlist(:)
        integer, intent(out) :: iostat
        character(*), intent(inout) :: iomsg

        call dtv%import_station(unit)

        iostat = 0
    end subroutine read_station

    subroutine import_station(this, unit)
        implicit none
        class(station), intent(inout) :: this
        integer, intent(in) :: unit
        character(256) :: header, footer
        integer ns

        read (unit, '(A)') header !> Header
        read (unit, *) ns
        if (ns > 0) then
            if (allocated(this%zloc)) then
                deallocate (this%zloc)
            end if
            allocate (this%zloc(ns))
            read (unit, *) this%zloc

            if (allocated(this%yloc)) then
                deallocate (this%yloc)
            end if
            allocate (this%yloc(ns))
            read (unit, *) this%yloc

            if (allocated(this%xloc)) then
                deallocate (this%xloc)
            end if
            allocate (this%xloc(ns))
            read (unit, *) this%xloc

            this%ns = ns
        end if
        read (unit, '(A)') footer !> Footer
    end subroutine import_station

    subroutine export_station(this, unit)
        implicit none
        class(station), intent(in) :: this
        integer, intent(in) :: unit

        write (unit, '(A)') ">STATION INFO"
        write (unit, '(I6)') this%ns
        write (unit, *) "Z:"
        write (unit, FmtFloat) this%zloc
        write (unit, *) "Y:"
        write (unit, FmtFloat) this%yloc
        write (unit, *) "X:"
        write (unit, FmtFloat) this%xloc
        write (unit, '(A)') ">END STATION"
    end subroutine export_station

    subroutine write_station(dtv, unit, iotype, vlist, iostat, iomsg)
        implicit none
        class(station), intent(in) :: dtv
        integer, intent(in) :: unit
        character(*), intent(in) :: iotype
        integer, intent(in) :: vlist(:)
        integer, intent(out) :: iostat
        character(*), intent(inout) :: iomsg

        call dtv%export_station(unit)

        iostat = 0
    end subroutine write_station

    subroutine destruct_station(this)
        implicit none
        type(station), intent(inout) :: this

        if (allocated(this%xloc)) then
            deallocate (this%xloc)
        end if
        if (allocated(this%yloc)) then
            deallocate (this%yloc)
        end if
        if (allocated(this%zloc)) then
            deallocate (this%zloc)
        end if
        this%ns = 0
    end subroutine destruct_station

end module station_module
program Test
    use station_module
    implicit none
    type(station) :: pt, pt1, pt2

    pt = station(4)

    write(*, *) pt

    call pt%export_station(6)

end program Test
 >STATION INFO     4Z:  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
 Y:  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00X:  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00>END STATION
>STATION INFO
     4
 Z:
  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
 Y:
  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
 X:
  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
>END STATION
输出:

module station_module
    implicit none

    character(8), parameter :: FmtFloat = '(5E15.7)'

    type :: station
        integer, private :: ns = 0
        real, public, allocatable :: xloc(:), yloc(:), zloc(:)
    contains
        procedure, public :: import_station
        procedure, public :: export_station
        procedure, private :: read_station
        generic, public :: read (formatted) => read_station
        procedure, private :: write_station
        generic, public :: write (formatted) => write_station
        final :: destruct_station
    end type station

    interface station
        module procedure new_station
    end interface station

contains

    function new_station(n) result(t)
        implicit none
        integer, intent(in) :: n
        type(station) :: t

        if (n > 0) then
            allocate (t%zloc(n))
            allocate (t%yloc(n))
            allocate (t%xloc(n))
            t%ns = n
        end if
    end function new_station

    subroutine read_station(dtv, unit, iotype, vlist, iostat, iomsg)
        implicit none
        class(station), intent(inout) :: dtv
        integer, intent(in) :: unit
        character(*), intent(in) :: iotype
        integer, intent(in) :: vlist(:)
        integer, intent(out) :: iostat
        character(*), intent(inout) :: iomsg

        call dtv%import_station(unit)

        iostat = 0
    end subroutine read_station

    subroutine import_station(this, unit)
        implicit none
        class(station), intent(inout) :: this
        integer, intent(in) :: unit
        character(256) :: header, footer
        integer ns

        read (unit, '(A)') header !> Header
        read (unit, *) ns
        if (ns > 0) then
            if (allocated(this%zloc)) then
                deallocate (this%zloc)
            end if
            allocate (this%zloc(ns))
            read (unit, *) this%zloc

            if (allocated(this%yloc)) then
                deallocate (this%yloc)
            end if
            allocate (this%yloc(ns))
            read (unit, *) this%yloc

            if (allocated(this%xloc)) then
                deallocate (this%xloc)
            end if
            allocate (this%xloc(ns))
            read (unit, *) this%xloc

            this%ns = ns
        end if
        read (unit, '(A)') footer !> Footer
    end subroutine import_station

    subroutine export_station(this, unit)
        implicit none
        class(station), intent(in) :: this
        integer, intent(in) :: unit

        write (unit, '(A)') ">STATION INFO"
        write (unit, '(I6)') this%ns
        write (unit, *) "Z:"
        write (unit, FmtFloat) this%zloc
        write (unit, *) "Y:"
        write (unit, FmtFloat) this%yloc
        write (unit, *) "X:"
        write (unit, FmtFloat) this%xloc
        write (unit, '(A)') ">END STATION"
    end subroutine export_station

    subroutine write_station(dtv, unit, iotype, vlist, iostat, iomsg)
        implicit none
        class(station), intent(in) :: dtv
        integer, intent(in) :: unit
        character(*), intent(in) :: iotype
        integer, intent(in) :: vlist(:)
        integer, intent(out) :: iostat
        character(*), intent(inout) :: iomsg

        call dtv%export_station(unit)

        iostat = 0
    end subroutine write_station

    subroutine destruct_station(this)
        implicit none
        type(station), intent(inout) :: this

        if (allocated(this%xloc)) then
            deallocate (this%xloc)
        end if
        if (allocated(this%yloc)) then
            deallocate (this%yloc)
        end if
        if (allocated(this%zloc)) then
            deallocate (this%zloc)
        end if
        this%ns = 0
    end subroutine destruct_station

end module station_module
program Test
    use station_module
    implicit none
    type(station) :: pt, pt1, pt2

    pt = station(4)

    write(*, *) pt

    call pt%export_station(6)

end program Test
 >STATION INFO     4Z:  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
 Y:  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00X:  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00>END STATION
>STATION INFO
     4
 Z:
  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
 Y:
  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
 X:
  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
>END STATION

常规子程序
export\u station
产生我所期望的结果。两个
write
语句之间会产生新行,而派生类型的
write
语句不会产生新行。

这里有两类输出语句:父语句和子语句。第一种情况下的父输出语句是
write(*,*)pt

当第一个是父语句时,通过
write\u station
调用
export\u station
将导致write语句存在子输出语句。当用户直接调用导出站时,这些写入语句本身就是父输出语句

子数据传输语句和父数据传输语句之间的一个显著区别是,父语句在数据传输之前和之后定位文件。也就是说,当
write(unit,*)”Z:“
完成时,仅当transfer语句是父语句时,才将文件定位在刚刚写入的记录之后

因此,您可以看到新行:这只是简单地放在书面记录之后

子数据传输语句在完成时不定位文件,不会影响新行



我目前无法使用测试机,所以这部分是推测性的。您可以显式写入从
new\u line(“”)
返回的新行字符,作为子传输语句输出的一部分。由于子语句中的
advance='no'
将被忽略,您可以在这两种情况下使用它,显式控制新行的写入位置,而不是依赖当前存在的拆分记录方法。

英特尔论坛上也提出了这一问题。我回答说,“用户定义的派生类型I/O都是非前进的(您不能更改)。如果您想要换行,您必须显式地编写它们(例如使用/格式)。”

英特尔论坛上也提出了这一问题。我回答说,“用户定义的派生类型I/O都是非前进的(你不能改变它)。如果你想要换行,你必须显式地写它们(例如使用a/format)。”这是一个更简洁的陈述,可能比这里的注释更值得作为一个答案,@stevelionel。你的答案是正确的,所以我不想踩你的脚,但如果你同意的话。。。完成!仅仅因为我是对的并不意味着我解释得很好;)。但是说真的,很少有Fortran技术问题有多重解释。只是为了更清楚地说明这一点:像
WRITE(unit,,(a/))
这样的东西就起到了作用。