Fortran读取含字符串与数值的二进制文件问题求助
问题解答
核心结论
如果目标文件是文本头+无格式二进制数据的混合格式,确实需要调整文件打开方式来读取后续数值数组。Fortran无法在同一个打开的文件句柄下切换FORMATTED和UNFORMATTED模式,推荐两种可行方案:
方案1:分两次打开文件(先读文本,再读二进制)
先以FORMATTED模式读取7行文本头,记录文本结束后的字节位置,关闭文件后再以UNFORMATTED模式重新打开并定位到该位置,最后读取数组。
PROGRAM READ_MIXED_FILE IMPLICIT NONE INTEGER, PARAMETER :: NUM_HEADER = 7 CHARACTER(LEN=256) :: header_line INTEGER :: fu, i, pos_after_header, arr_size REAL, ALLOCATABLE :: x(:), y(:), z(:) INTEGER, ALLOCATABLE :: int_arr(:) ! 读取文本头并记录结束位置 OPEN(fu, FILE='target_file.bin', STATUS='OLD', ACTION='READ', FORM='FORMATTED') DO i = 1, NUM_HEADER READ(fu, '(A)') header_line ! 从文本头提取数组大小,示例:若某行含"ARR_SIZE: 1000" ! IF (INDEX(header_line, 'ARR_SIZE') /= 0) READ(header_line(INDEX(header_line,':')+2:), *) arr_size END DO INQUIRE(fu, POS=pos_after_header) CLOSE(fu) ! 以无格式模式打开并定位 OPEN(fu, FILE='target_file.bin', STATUS='OLD', ACTION='READ', FORM='UNFORMATTED', ACCESS='STREAM') READ(fu, POS=pos_after_header) ! 调用读取子程序 CALL READ_REAL_ARRAY(fu, arr_size, x) CALL READ_REAL_ARRAY(fu, arr_size, y) CALL READ_REAL_ARRAY(fu, arr_size, z) CALL READ_INT_ARRAY(fu, arr_size, int_arr) CLOSE(fu) END PROGRAM ! 实型数组读取子程序 SUBROUTINE READ_REAL_ARRAY(unit, size, arr) INTEGER, INTENT(IN) :: unit, size REAL, ALLOCATABLE, INTENT(OUT) :: arr(:) ALLOCATE(arr(size)) READ(unit) arr END SUBROUTINE ! 整型数组读取子程序 SUBROUTINE READ_INT_ARRAY(unit, size, arr) INTEGER, INTENT(IN) :: unit, size INTEGER, ALLOCATABLE, INTENT(OUT) :: arr(:) ALLOCATE(arr(size)) READ(unit) arr END SUBROUTINE
方案2:用STREAM模式一次性打开(推荐)
STREAM模式支持直接按字节操作文件,无需切换打开模式,同时兼容文本和二进制数据的读取:
PROGRAM READ_MIXED_STREAM IMPLICIT NONE INTEGER, PARAMETER :: NUM_HEADER = 7 CHARACTER(LEN=256) :: header_line INTEGER :: fu, i, arr_size REAL, ALLOCATABLE :: x(:), y(:), z(:) INTEGER, ALLOCATABLE :: int_arr(:) ! 以STREAM模式打开文件 OPEN(fu, FILE='target_file.bin', STATUS='OLD', ACTION='READ', ACCESS='STREAM') ! 读取文本头 DO i = 1, NUM_HEADER READ(fu, '(A)') header_line ! 提取数组大小 END DO ! 直接读取二进制数组 CALL READ_REAL_ARRAY(fu, arr_size, x) CALL READ_REAL_ARRAY(fu, arr_size, y) CALL READ_REAL_ARRAY(fu, arr_size, z) CALL READ_INT_ARRAY(fu, arr_size, int_arr) CLOSE(fu) END PROGRAM ! 实型数组读取子程序(STREAM模式通用) SUBROUTINE READ_REAL_ARRAY(unit, size, arr) INTEGER, INTENT(IN) :: unit, size REAL, ALLOCATABLE, INTENT(OUT) :: arr(:) ALLOCATE(arr(size)) READ(unit) arr END SUBROUTINE ! 整型数组读取子程序(STREAM模式通用) SUBROUTINE READ_INT_ARRAY(unit, size, arr) INTEGER, INTENT(IN) :: unit, size INTEGER, ALLOCATABLE, INTENT(OUT) :: arr(:) ALLOCATE(arr(size)) READ(unit) arr END SUBROUTINE
关键注意事项
- 数组大小
arr_size必须准确,建议从文本头中提取(生成文件时应将数组大小写入头信息),否则会导致读取错误; - 若
INQUIRE(POS=...)定位不准,可手动计算文本头总字节数(每行长度+换行符字节:Windows为2字节,Linux为1字节); - 读取模式必须与文件生成时的写入模式一致:如果数组是用
FORM='UNFORMATTED'写入的,读取时必须用相同模式。
内容的提问来源于stack exchange,提问作者Moonwalk
相关产品推荐
相关产品推荐

