1.7. 文件输入输出

Fortran 拥有丰富且易用的文件 I/O 能力,尤其擅长处理格式化表格数据。

1.7.1. 文件操作基础

1.7.1.1. 核心步骤

1. 打开文件(open 语句) → 分配通道号
2. 读写文件(read / write 语句)
3. 关闭文件(close 语句)
program file_demo
    implicit none
    integer :: unit

    ! 打开文件
    open(newunit=unit, file="data.txt", status="unknown")

    ! 读写操作...

    ! 关闭文件
    close(unit)
end program

1.7.1.2. 文件通道号

integer :: unit

! 方式 1:手动指定(传统)
open(unit=10, file="data.txt")

! 方式 2:newunit(Fortran 2003+,推荐)
! 自动分配未使用的通道号
open(newunit=unit, file="data.txt")
write(*, *) "通道号:", unit
close(unit)

小技巧

始终使用 newunit——它自动选择可用的通道号,避免冲突。

1.7.2. open 语句

! 基本格式
open(unit, file, status, action, position, iostat, errmsg)

! 实际示例
integer :: unit, ios
character(256) :: err_msg

open(newunit=unit, file="result.dat", status="replace", &
     action="write", iostat=ios, iomsg=err_msg)
if (ios /= 0) then
    write(*, *) "打开失败:", trim(err_msg)
    stop
end if

1.7.2.1. status 参数

status

含义

文件存在

文件不存在

"old"

读取已有文件

正常打开

出错

"new"

创建新文件

出错

创建

"replace"

替换已有文件

清空重新创建

创建新文件

"scratch"

临时文件

(关闭时自动删除)

创建临时文件

"unknown"

由编译器决定

正常打开

创建

1.7.3. 文本文件读写

1.7.3.1. 写入

integer :: i, unit
real :: x

open(newunit=unit, file="output.txt", status="replace", action="write")

! 自由格式写入
write(unit, *) "Hello, Fortran!", 42, 3.14

! 格式化写入
do i = 1, 10
    x = i * 1.5
    write(unit, '(I5, F10.3)') i, x
end do

close(unit)

! 标准输出:unit = 6 或使用 *
write(*, *) "输出到屏幕"        ! * 表示标准输出
write(6, *) "同上"

1.7.3.2. 读取

integer :: i, unit, ios
real :: x

open(newunit=unit, file="input.txt", status="old", action="read")

! 逐行读取
do
    read(unit, *, iostat=ios) i, x
    if (ios /= 0) exit          ! 文件结束或出错
    write(*, *) i, x
end do

close(unit)

小心

read(..., iostat=ios) 检查 I/O 状态: - ios == 0:正常 - ios < 0:文件结束 (EOF) - ios > 0:发生错误

1.7.4. 格式化描述符

integer :: i = 42
real(8) :: x = 3.14159265358979_dp
character(10) :: name = "Fortran"

! 各格式示例
write(*, '(I5)')     i            !   "   42" (整数, 宽 5)
write(*, '(I0)')     i            !   "42" (I0 = 紧凑输出)
write(*, '(F8.3)')   real(i)      !   "  42.000" (浮点, 总宽8, 小数3)
write(*, '(E12.4)')  x            !   "0.3142E+01" (科学计数)
write(*, '(ES12.4)') x            !   "  3.1416E+00" (现代科学计数)
write(*, '(A)')      name         !   "Fortran"
write(*, '(A10)')    name         !   "   Fortran" (右对齐, 宽10)
write(*, '(L1)')     .true.       !   "T"
write(*, '(1X, A)')  name         !   前导空格

! 组合格式
write(*, '(A, I0, A, F8.3)') "i=", i, ", x=", x

描述符

含义

示例输出

Iw

整数,宽度 w

I5 → `` 42``

I0

整数,紧凑格式

I0 → 42

Fw.d

浮点,总宽 w,小数 d 位

F8.3 → `` 42.000``

Ew.d

科学计数

E12.4 → 0.4210E+02

ESw.d

现代科学计数(推荐)

ES12.4 → `` 4.2000E+01``

Aw

字符串

A10 → `` Fortran``

Lw

逻辑值(T/F)

L1 → T

wX

空格

3X → `` ``

/

换行

/ → 新行

1.7.5. namelist(命名列表)

Fortran 特有的强大功能:按名称读写变量组。

program namelist_demo
    implicit none
    integer :: n = 100
    real    :: tol = 1e-6_dp
    logical :: debug = .false.
    character(50) :: method = "RK4"

    ! 定义 namelist
    namelist /params/ n, tol, debug, method

    ! 写入
    open(10, file="params.nml", status="replace")
    write(10, nml=params)
    close(10)

    ! 读取(可修改部分参数,不要求全部提供)
    n = 0; debug = .true.
    open(10, file="params.nml", status="old")
    read(10, nml=params)
    close(10)

    write(*, *) n, tol, debug, method
end program

生成的 params.nml 文件内容:

&PARAMS
  N=100,
  TOL=0.100000000000000E-005,
  DEBUG=F,
  METHOD="RK4",
/

小技巧

Namelist 非常适合**配置文件**: - 可读性强,易于手工编辑 - 可选择性修改部分参数 - 无需关心格式描述符

1.7.6. 二进制文件

integer, parameter :: n = 100
real(8) :: data(n)
integer :: unit

! 初始化
data = [ (i * 1.0_dp, i = 1, n) ]

! 写二进制文件
open(newunit=unit, file="data.bin", &
     form="unformatted", status="replace", &
     access="stream")               ! 流式访问(推荐)
write(unit) data
close(unit)

! 读取
open(newunit=unit, file="data.bin", &
     form="unformatted", status="old", access="stream")
read(unit) data
close(unit)

备注

access="stream" (Fortran 2003+) 以字节流方式读写,与 C 兼容。 传统方式使用 access="sequential" 或 access="direct"。

1.7.7. 文件操作常用函数

integer :: ios, unit
logical :: exists

! 检查文件是否存在
inquire(file="data.txt", exist=exists)

! 检查文件是否已打开
inquire(file="data.txt", opened=exists, number=unit)

! 获取文件大小
inquire(file="data.txt", size=ios)

! 检查读写状态
inquire(unit=10, iostat=ios)

! 删除文件
open(unit=10, file="temp.txt")   ! 先打开
close(10, status="delete")        ! 关闭时删除