Fortran 未格式化文件中的意外“填充”

Posted

技术标签:

【中文标题】Fortran 未格式化文件中的意外“填充”【英文标题】:Unexpected "padding" in a Fortran unformatted file 【发布时间】:2012-02-03 18:57:31 【问题描述】:

我不明白 Fortran 中无格式文件的格式。

例如:

open (3,file=filename,form="unformatted",access="sequential")
write(3) matrix(i,:)

将矩阵的一列输出到文件中。我发现它在文件的两端填充了 4 个字节,但是我真的不明白为什么或如何控制这种行为。有没有办法去掉填充?

【问题讨论】:

更改了标题,因为我真的不喜欢该术语的误导性用法 - “二进制”。二进制表示以 2 为底,与您的问题没有直接关系。在某种程度上,您计算机上的几乎所有内容都是二进制的。这是现在的常用术语,但 fortran 的“未格式化”更接近。 这里有一些关于流的有用信息...star.le.ac.uk/~cgp/streamIO.html 这似乎与***.com/questions/8751154/… 重复,请不要多次发布您的问题? 【参考方案1】:

对于未格式化的 IO,Fortran 编译器通常在记录的开头和结尾写入记录的长度。大多数但不是所有编译器都使用四个字节。这有助于读取记录,例如末尾的长度有助于退格操作。您可以使用 Fortran 2003 的新 Stream IO 模式来抑制这种情况,该模式是为了与其他语言兼容而添加的。在您的公开声明中使用 access='stream'

【讨论】:

作为一个小提示,一些编译器(例如 Gfortran 和 Intel Fortran)通过使用子记录来支持大于 2 GB 的记录,尽管记录标记为 4 字节。【参考方案2】:

Fortran IO 是基于记录的,而不是基于流的。每次您通过write() 写入内容时,您不仅在写入数据,而且还在写入该记录的开始和结束标记。两个记录标记都是该记录的大小。这就是为什么在一次写入中写入一堆实数(一个记录:一个开始标记,一堆实数,一个结束标记)相对于在单独的写入中写入每个实数(多个记录,每个一个开始标记、一个实数和一个结束标记)。如果您要写下大型矩阵,这一点非常重要,因为如果写得不正确,您可能会使职业膨胀。

【讨论】:

您所说的仅适用于“顺序”访问 @steabert:这是最常用的 (99.999 %)。 我的代码大约有一半使用“直接”访问——所以这对我来说只有 50%:P【参考方案3】:

出于这个确切原因,我从未对未格式化的输出使用顺序访问。然而,这取决于应用程序,有时使用记录长度指示器会很方便(尤其是对于非结构化数据)。正如steabert 在Looking at binary output from fortran on gnuplot 中所建议的那样,您可以通过使用关键字参数ACCESS = 'DIRECT' 来避免这种情况,在这种情况下您需要指定记录长度。该方法便于高效存储大型多维结构化数据(记录长度不变)。以下示例写入一个大小等于数组大小的未格式化文件:

REAL(KIND=4),DIMENSION(10) :: a = 3.141
INTEGER                    :: reclen

INQUIRE(iolength=reclen)a
OPEN(UNIT=10,FILE='direct.out',FORM='UNFORMATTED',&
     ACCESS='DIRECT',RECL=reclen)
WRITE(UNIT=10,REC=1)a
CLOSE(UNIT=10)

END

请注意,这不是可移植性的理想方法。在使用直接访问写入的未格式化文件中,没有关于每个元素大小的信息。描述数据大小的自述文本文件对我来说很好,我更喜欢这种方法而不是顺序模式下的填充。

【讨论】:

【参考方案4】:

Fortran Unformatted IO 我非常熟悉使用 Intel 和 Gnu 编译器的不同输出。幸运的是,我可以追溯到 1970 年代 IBM 的丰富经验使我能够解码事物。 Gnu 用 4 字节整数计数器填充记录,给出记录长度。 Intel 使用一个 1 字节计数器和一些嵌入的编码值来表示连续记录或计数的结束。即使只使用了 1 个字节,记录长度仍然可以很长。 我有由 Gnu 编译器编译的软件,我必须对其进行修改,以便它可以读取任一编译器生成的未格式化文件,因此它必须检测它找到的格式。使用 Gnu 的 fgetc 或以流模式打开文件,读取由 Intel 编译器生成的未格式化文件(遵循“旧”IBM 时代)需要“永远”。将文件转换为 Gnu 预期的结果最多 100 倍更快。这取决于您的文件大小,如果您想打扰检测和转换。我将程序启动时间(打开一个未格式化的大文件)从 5 分钟减少到 10 秒。我必须添加重新转换的选项如果用户想要将文件带回英特尔编译的程序,请再次返回。这很痛苦,但是你去吧。

【讨论】:

以上是关于Fortran 未格式化文件中的意外“填充”的主要内容,如果未能解决你的问题,请参考以下文章

Fortran 错误:单元连接到格式化文件

可以将 Fortran 数组保存为 .npy 格式吗?

用 Python 编写 Fortran 无格式文件

未捕获的语法错误:意外的令牌:getJSON

NVMe SSD 上的 GFortran 未格式化 I/O 吞吐量

Fortran中生成的.dat文件,怎么用tecplot打开?