用 Python 读写 Fortran 格式化的数据
Fortran 至今仍然是学术界流行的编程语言。得益于其在科学计算方面的出色表现(以及某些历史传承),众多的科研软件都基于 Fortran 编写。同时,很多文件格式也以 Fortran 的格式化输出风格定义。大地测量学领域众多的数据格式都使用 Fortran 格式定义,比如 RINEX、IONEX、SINEX、SP3 等。
Fortran 对输入输出的格式化要求严谨,使用 Python 自己的字符串格式化语法得到的文本很难符合其规范(或者代码可读性很差)。本文介绍在 Python 中使用 Fortran 格式化风格的包:fortranformat,可以使用它对代码进行一些优化。
安装
fortranformat 支持 Python 2 和 Python 3,其代码目前以 MIT 许可证托管于 Bitbucket。你可以直接使用 pip 命令来安装 fortranformat:
1 | $ pip install fortranformat |
使用
fortranformat 使用起来非常简单,它只定义了两个接口:FortranRecordReader
和 FortranRecordWriter
,分别用于数据的输入和输出。使用特定的 Fortran 格式化语法实例化接口后,就可以进行数据的读写操作。
以 Fortran 格式输入
以 RINEX 2.11 为例,其首行的格式定义为 (F9.2, 11X, 2(A1, 19X), A20)
,你可以使用 fortranformat 以如下方法读取数据:
1 | import fortranformat as ff |
如代码所示,FortranRecordReader
对象有一个 read
方法,它从你输入的字符串中读取并解析数据,最终返回一个列表。
以 Fortran 格式输出
相比读取 Fortran 格式的数据,以 Fortran 约定的格式化风格输出其实才是难题。但 fortranformat
能够很好的处理这些问题。比如输出类似 -.6789 或 .1234567D+02 这样看上去有些 “奇怪” 数字:
1 | import fortranformat as ff |
如代码所示,FortranRecordWriter
对象有一个 write
方法,可以很方便得将数据列表转换为你期望(或 Fortran 期望)的文本。甚至连异常情况下的表现也是相同的。
配置行为
各个 Fortran 编译器的行为可能略有不同,并且,为了表现得更 Pythonic,fortranformat 未完全模仿 Fortran 的行为。但你可以通过进行设置来达到你想要的效果。
RET_UNWRITTEN_VARS_NONE
Fortran 从字符串解析数据时,但数据为空时通常会使用对应数据类型的默认值填充。fortranformat 的默认行为不同,它将空值设置为 None
。你可以配置 RET_UNWRITTEN_VARS_NONE
来禁用这一行为。示例:
1 | import fortranformat as ff |
RET_WRITTEN_VARS_ONLY
上文的变量配置的是数据在原始文本中不存在时如何填充的行为。RET_WRITTEN_VARS_ONLY
也跟这种情况有关。它设置的是:仅返回存在的变量的值。示例如下:
1 | import fortranformat as ff |
演示
以读取一段 RINEX 格式的广播星历文件为例:
1 | import fortranformat as ff |
将上面读取的数据 brdc_orb
仍以 RINEX 格式输出:
1 | epo_writer = ff.FortranRecordWriter(epo_fmt) |
可以看出:经 fortranformat 格式化的字符串与原 RINEX 文本数据完全一致。