fortran - 从未格式化的文件中读取字符串(可变记录长度)

标签 fortran binaryfiles

我有一个未格式化的 Fortran 文件,其中包含不同长度的字符串,并且我在使用 Fortran 本身读取这些字符串时遇到问题。

示例程序:

program test
implicit none
character(len=200) :: line

open(32,file="testfile",form="unformatted",action="write")
write(32) "A test string"
write(32) "Another longer test string"
close(32)

open(33,file="testfile",form="unformatted",action="read")
read(33) line
write(6,*) trim(line)
read(33) line
write(6,*) trim(line)
close(33)

end program test

失败(用 gfortran 编译):

At line 11 of file test.f90 (unit = 33, file = 'testfile')
Fortran runtime error: I/O past end of record on unformatted file

我可以通过尝试减少长度和退格(read_string 子例程)进行读取来使其工作,但这看起来效率很低:

program test
implicit none
character(len=200) :: line

open(32,file="testfile",form="unformatted",action="write")
write(32) "A test string"
write(32) "Another longer test string"
close(32)

open(33,file="testfile",form="unformatted",action="read")
call read_string(33,line)
write(6,*) trim(line)
call read_string(33,line)
write(6,*) trim(line)
close(33)

contains

subroutine read_string(u,string)
integer, intent(in) :: u
character(len=*), intent(out) :: string
integer :: i, error

do i=len(string),0,-1
  read(u,iostat=error) string(:i)
  if (error == 0) then
    string(i+1:) = ''
    exit
  end if
  backspace(u)
end do

end subroutine read_string

end program test

是否有更好的方法从未格式化的文件中读取可变长度字符串?

最佳答案

我稍微修改了您的示例程序,以二进制形式读取文件。这适用于英特尔的编译器; gfortran 不知道二进制格式,所以 ymmv。 看看我的想法是从哪里得到的 Intel's reference on record types

program test
implicit none
character(len=200) :: line
integer(4) recl_at_start, recl_at_end

open(32,file="testfile",form="unformatted",action="write")
write(32) "A test string"
write(32) "Another longer test string"
close(32)

! initialization is required to fill the line with blanks
! because trim() does not work on line filled with zero characters
line = ""

open(33,file="testfile",form="binary",action="read")

read(33) recl_at_start
read(33) line(1:recl_at_start)
read(33) recl_at_end
write(6,*) trim(line)

read(33) recl_at_start
read(33) line(1:recl_at_start)
read(33) recl_at_end
write(6,*) trim(line)

close(33)

end program test

它的输出是

A test string
Another longer test string

既然你知道了行的长度,trim()就不再需要了。只需使用

write(6,*) line(1:recl_at_start)

这也可以防止您向数据添加“较短的测试字符串”时出现问题。

关于fortran - 从未格式化的文件中读取字符串(可变记录长度),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19464417/

相关文章:

fortran - GNU Fortran/OpenMP 程序如何设置和检索 stacksize-var ICV?

pointers - 这种使用字符串指针安全吗?

fortran - LAPACK DGETRF+DGETRI 失败

assembly - COBOL 是否强制一行的前 6 个字符为数字,因为它更容易编译为二进制可执行文件?

C# 检查文件的二进制读取器结尾

pointers - 为什么 Fortran 指针总是可变的

fortran - 将 FFTW 计划传递给 Fortran 子例程

C - 二进制读取,fread 是反转顺序

c++ - 在 C++ 2 中读取二进制文件

python - 在 Python 中准备一个非常简单的 64 位 float 列表,用 Gfortran 编写为 UNFORMATTED 是否容易?