【问题标题】:Writing large Fortran binary files with access=stream使用 access=stream 编写大型 Fortran 二进制文件
【发布时间】:2018-05-29 22:23:05
【问题描述】:

我在理解我使用 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 时出现,我已更新文本以反映这一点。

【问题讨论】:

  • 对于较小的 m 值,它是否按预期工作?
  • @ptb 我认为m 较小值的文件大小始终为m^3+8,然后它切换到m^3+24 介于m=512m=1024 之间的某个位置。
  • @VladimirF 我不知道额外的字节到底在哪里。我没有尝试用 C 写类似的文件。
  • 只是出于好奇,如果将status='replace' 添加到open 命令并删除form 会发生什么
  • @VladimirF 也许这更相关:stackoverflow.com/questions/15608421/… 我不禁认为这与 Fortran 二进制文件的 ~2Gb 限制有关。

标签: fortran binaryfiles intel-fortran fortran2003


【解决方案1】:

这个问题可以通过在 Fortran 的open 命令中添加status='replace' 来解决。 与编译器无关

使用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 生成一个大小为8 + 4 = 12 字节的文件“测试”。其中8 是标准的Fortran 二进制页眉和页脚,4a 的字节大小。在第二个write 语句中,即使设置了access='stream',也只会覆盖先前生成的'test' 的第一个4 字节,使文件大小为12 字节!解决办法是把第二条写语句改成

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

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

【讨论】:

  • 如果我运行上面编写的代码,使用gfortran 8.1.0 编译,我会生成一个大小为 12 字节的文件,该文件不会被第二个 write 语句替换。我认为这不仅仅是 ifort 的旧版本。
  • 对不起,是的,我没有意识到您正在有效地打开文件进行读写,对于顺序文件不会发生这种情况,但是在流文件中您可以在任何位置读写使用pos=,因此您无法自动删除其余部分。
猜你喜欢
  • 2015-11-29
  • 2016-09-20
  • 2019-11-24
  • 1970-01-01
  • 1970-01-01
  • 2010-12-02
  • 2016-03-03
  • 1970-01-01
  • 2011-12-07
相关资源
最近更新 更多