在Fortran中打开二进制文件:状态、格式、访问

9
我已经使用Fortran工作多年,但是文件I/O对我来说仍然模糊不清。我的理解仅限于statusformaccessrecl的某些用例,因为我只在研究生阶段需要过这些内容。
我知道Fortran二进制文件在文件顶部有额外的信息来描述文件大小。但是这之前从未成为我的问题,因为我只需要在Fortran代码中处理Fortran文件,其中额外的信息是必要的,但是看不见的。 但是我如何在Fortran中打开一个扁平的二进制文件? 过去,我可能会像这样使用Fortran打开Fortran二进制文件:
open(id,file=file_name,status='old',
     +     form='unformatted',access='direct',recl=4,iostat=ok)
      if (ok .ne. 0) then
        write(1,20) id,ok,file_name
                else
        write(1,21) id,file_name

但是,对于一个没有Fortran头信息的平面二进制文件,这种情况会怎样改变呢?更重要的是,有哪些好链接可以详细描述这些术语:statusformaccessrecl


1
当我说“C++”二进制文件时,我指的只是由C++程序编写的原始、平面的二进制文件。文件格式可以是任何形式,一个由1字节整数行和列填充的平面二进制文件。显然,我的主要问题是尝试在Fortran中读取二进制文件,如果该文件没有通常的Fortran头,则会出现问题。 - john_science
3
Fortran直接读写二进制文件中没有额外的头信息!使用顺序非格式化文件会得到记录控制字,但是直接IO非格式化文件就像它们可以。将8字节实数写入磁盘将会给你一个恰好包含这八个字节的文件。 - haraldkl
1
@haraldkl已经击败了我。只有顺序访问文件才能给你额外的位数,而不知道这一点导致我遭受了很多调试的痛苦。 - Tim Whitcomb
谢谢,Haraldkl。我刚试了一下,你说得完全正确。那是很重要的信息。如果那是一个帖子,你会得到一个点赞。 - john_science
请参阅 https://dev59.com/Hmoy5IYBdhLWcg3wJKoq#8751662。 - M. S. B.
显示剩余2条评论
4个回答

12

我不太喜欢这么做,但是如果我希望在这篇文章中找到答案,前进的方向并不清晰。因此,以下是前进的方法。

简短的版本

在Fortran 77/90中,要打开一个标准的Fortran二进制文件,你可能会写:

OPEN (5, FILE="myFile.txt")

但是要打开一个扁平的非Fortran二进制文件,你需要编写类似以下的代码:

OPEN(5, file="myFile.txt", form='unformatted', access='direct', recl=1)

这种差异是因为Fortran风格的二进制文件在每个“记录”周围都有4字节的头部和尾部。这些头/尾描述了记录中包含的数据大小。(在最常见的情况下,你遇到的每个二进制文件只会有一个记录。)

详细说明

Fortran假设许多默认的open参数。实际上,我们的原始示例可以以以下冗长形式编写,以显示所有默认值。

OPEN (5, FILE="myFile.txt") 
OPEN (5, FILE="myFile.txt", FORM="FORMATTED", 
     +   ACCESS="SEQUENTIAL", STATUS="UNKNOWN")

让我们来看看每个参数:

  • FORM 定义了一个文件是由文本 (form='formatted') 还是二进制数据 (form='unformatted') 组成。

  • ACCESS 定义了您是按顺序 (access='sequential') 还是按任意顺序 (access='direct') 从文件中读取数据。

  • RECL 定义了每个记录需要的字节数。例如,recl=1 表示记录长度为 1 个字节,可能是 1 字节的整数。

  • STATUS 定义了文件是否已经存在。参数 STATUS="UNKNOWN" 表示该文件可能尚不存在,但如果不存在,则将创建它。如果您想防止写入旧文件的可能性,请使用: STATUS="OLD"。同样,如果您知道文件尚不存在,则应使用: STATUS="NEW"

更多信息:

这些打开语句也会影响接下来的读/写/关闭语句。在我的原始帖子中,我需要知道如果打开直接访问文件,则必须写入直接访问文件。(也就是说,在您的二进制文件中不会包含Fortran头/尾。)然而,Fortran 的默认功能是创建带有 Fortran 标头和脚注的顺序访问文件。

有关 Fortran 77/90 中的 open 语句的更多信息,请参阅以下在线资源:

Bishop 大学 Lin Jinsen 的一个不错的页面(非常感谢)。

IBM 官方编译器的略微更正式的文档


这是一个老问题,但扩展答案以包括如何从“非Fortran二进制文件”读取记录的示例将是有用的。特别是,涉及读取派生类型的情况,我猜这是处理二进制文件时常见的情况。另一个问题是是否可以一次读取整个派生类型数组(即,我一次将整个文件读入数组中)。 - M.E.

5

注意,给定 recl 的记录长度默认为带有非格式化记录的 4 字节字数(至少在 Intel 编译器上,请使用 byterecl 指定其他选项),因此您可能需要指定编译器选项或使用 recl=1

就目前代码而言,使用非格式化和直接读取,您只需要选择适当的记录长度即可确保正确读取数据。但是,某些 FORTRAN 编译器不总是对非格式化二进制文件进行友好处理,我建议您今后采用 HDF5

如果可用,您的编译器可以允许 recordtype='stream'

open (id, file=file_name, status='old', form='unformatted' &
        , access='stream', iostat=ios)
! read (id, pos=1) someValue

感谢您指定recl默认为Intel编译器的4字节字。奇怪的是,我在英特尔文档中找不到它的提及。 - umbersar

1
您可以使用access='stream'命令告诉open在Fortran 2003中使用新的Stream IO模式。

4
你为什么还在使用Fortran 77?现在几乎没有编译器无法编译F90的了。请问需要帮助吗? - haraldkl
2
@haraldkl - 然而,有很多无知的用户拒绝学习新版本,坚持使用F77,不管听起来多么愚蠢。为什么不用Fortran IV呢?我总是这样问。 - Rook
1
你可以使用F77将现有代码编译成静态库,然后将其链接到F90项目中。 - bdforbes
1
几乎没有向后兼容性问题,通过在打开语句中使用流关键字,您甚至不必使用自由格式文件,可以坚持使用固定格式。唯一的问题是,F77编译器将无法处理打开处理。但是我不知道这可能会在哪台机器上引起问题,因为F90现在相当老了,编译器有时间适应;)如果需要证据,请指向标准,我认为F90中唯一删除的功能是H-Format描述符之类的。无论如何,编译器很可能仍然支持甚至那个。 - haraldkl
1
在F2003中,我认为计算跳转和算术if已被删除。有关哪些编译器支持哪些功能的概述,请查看http://fortranwiki.org/fortran/show/Fortran+2003+status,确实有三个指示不支持流IO的编译器:Absoft、HP和PathScale... - haraldkl
显示剩余4条评论

1

如果您无法使用流访问,则必须使用直接访问。请参见此问题中的链接。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接