使用access = stream编写大型Fortran二进制文件

时间:2018-05-04 18:48:35

标签: fortran binaryfiles intel-fortran fortran2003

我在理解使用Fortran编写的二进制文件的格式时遇到了一些问题。我使用以下子例程将二进制文件写入磁盘:

SUBROUTINE write_field(d,m,outfile)

    IMPLICIT NONE    
    REAL, INTENT(IN) :: d(m,m,m)
    INTEGER, INTENT(IN) :: m
    CHARACTER(len=256), INTENT(IN) :: outfile

    OPEN(7,file=outfile,form='unformatted',access='stream')
    WRITE(7) d
    CLOSE(7)

END SUBROUTINE write_field

我对access=stream选项的理解是,这会抑制Fortran二进制文件附带的标准页眉和页脚(参见Fortran unformatted file format)。

如果我用m=512写一个文件,那么我的期望是该文件应该是4 x 512^3 bytes = 536870912 bytes ~ 513 Mb,但它们实际上比这长8个字节,来自536870920 bytes。我的猜测是这些额外的字节是4字节的页眉和页脚,我想用access='stream'来抑制它。

如果我用m=1024写一个文件,那么情况会让我感到困惑,那么我的期望是该文件应该是4 x 1024^3 bytes = 4294967296 ~ 4.1 Gb但实际上它们比这更长24(!)个字节,进来在4294967320 bytes。我不明白为什么这里有24个额外的字节,这似乎对应于6(!)页眉或页脚。

我的问题是:

(a)是否可以让Fortran编写没有页眉或页脚的二进制文件?

(b)如果(a)的答案是“否”,那么我可以确保较大的二进制文件具有与较小的二进制文件相同的页眉和页脚结构吗?

(c)如果(a)和(b)的答案都是“否”,那么我如何理解这些额外的页眉和页脚在文件中的位置。

我正在使用ifort(版本14.0.2),我正在一个小型Linux集群上编写二进制文件。

更新:当使用OSx运行相同的代码并使用gfortran 7.3.0编译时,二进制文件会出现预期的大小,因为它们总是4 x m^3 bytes,即使m=1024。所以这个问题似乎与较旧的编译器有关。

更新:事实上,只有在使用ifort 14.0.2时才会出现问题我已更新文本以反映这一点。

1 个答案:

答案 0 :(得分:2)

通过在Fortran status='replace'命令中添加open来解决此问题。 与编译器有关。

使用access='stream'且没有status='replace'时,旧的二进制文件不会被新的二进制文件自动替换,只是被覆盖到某个点(https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/676047)。这导致旧的二进制文件简单地将字节替换为新二进制文件的大小,同时保留任何附加字节和文件大小不变。如果新文件大小小于旧文件大小,则会出现此问题。由于文件上的时间戳已更新,因此难以诊断该问题,因此在使用ls -l查询时,该文件看起来是新的。

重新创建此问题的最小工作示例如下:

PROGRAM write_binary_test_minimal

    IMPLICIT NONE
    REAL :: a

    a=1.

    OPEN(7,file='test',form='unformatted')
    WRITE(7) a
    CLOSE(7)

    OPEN(7,file='test',form='unformatted',access='stream')
    WRITE(7) a
    CLOSE(7)

END PROGRAM write_binary_test_minimal

第一个write生成一个文件' test'大小为8 + 4 = 12个字节。其中8是标准的Fortran二进制页眉和页脚,4a的字节大小。在第二个write语句中,即使设置了access='stream',也只有先前生成的'测试的第一个4个字节。被覆盖,文件大小为12个字节!解决方法是将第二个写语句更改为

OPEN(7,file='test',form='unformatted',access='stream',status='replace')

使用明确的status='replace'来确保替换旧文件。