简体   繁体   English

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

[英]Write statement cannot produce new lines within user-defined formatted I/O procedures for derived type

I want to implement the user-defined I/O procedures for the derived types in my Fortran code. 我想在我的Fortran代码中为派生类型实现用户定义的I / O过程。 However, write statements within those procedures cannot produce new lines between two sequential write statements. 但是,这些过程中的write语句不能在两个顺序write语句之间产生新行。 The derived type and procedures are defined as below. 派生类型和过程定义如下。

The module: 模块:

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

We can see that the user-defined formatted write statement just call a regular subroutine named export_station , by which I expect the same result in both ways. 我们可以看到用户定义的格式化的write语句只调用一个名为export_station的常规子例程,我希望通过这两个方法得到相同的结果。

Here is my test program: 这是我的测试程序:

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

The output: 输出:

 >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

The regular subroutine export_station produces what I expect. 常规子例程export_station产生了我所期望的。 New lines are produced between two write statements, while write statement of the derived type does not. 在两个write语句之间生成新行,而派生类型的write语句则不生成。

This was also asked on the Intel forum. 这也是在英特尔论坛上提出的。 I replied there."User-defined derived-type I/O is all non-advancing (and you can't change this). If you want newlines you have to write them explicitly (using a / format, for example.)" 我回答说。“用户定义的派生类型I / O都是非进展的(你不能改变它)。如果你想要新行,你必须明确地写它们(例如,使用/格式)。”

There are two classes of output statements here: a parent and a child. 这里有两类输出语句:父语句和子语句。 The parent output statement in the first case is the write (*,*) pt . 第一种情况下的父输出语句是write (*,*) pt

When this first is the parent, then the call to export_station through write_station leads to the write statements there being child output statements. 当这首先是父母,然后调用export_station通过write_station导致写语句是有孩子的输出语句。 When export_station is called directly by the user those write statements are themselves parent output statements. 当用户直接调用export_station ,这些write语句本身就是父输出语句。

One significant difference between a child data transfer statement and a parent data transfer statement is that a parent statement positions the file prior to and after data transfer. 子数据传输语句和父数据传输语句之间的一个显着区别是父语句在数据传输之前和之后定位文件。 That is, when the write (unit,*) "Z:" completes the file is positioned after the record just written only when the transfer statement is a parent. 也就是说,当write (unit,*) "Z:"完成时,文件位于刚刚写入的记录之后,当转移语句是父语句时。

Thus, you see the new lines: this is simply placing after the written record. 因此,您会看到新的行:这只是放在书面记录之后。

A child data transfer statement, not positioning the file on completion, does not effect a new line. 子数据传输语句(不是在完成时定位文件)不会影响新行。


I don't have access to a test machine at the moment, so this part is speculative. 我目前无法访问测试机器,所以这部分是推测性的。 You can explicitly write a new line character returned from new_line('') as part of your output for the child transfer statement. 您可以显式写入从new_line('')返回的new_line('')作为子转移语句输出的一部分。 As advance='no' will be ignored in a child statement you could use that for both cases, explicitly controlling where new lines are written, rather than relying on the split record approach as currently exists. 由于advance='no'将在子语句中被忽略,您可以在两种情况下使用它,明确控制新行的写入位置,而不是依赖于当前存在的拆分记录方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM