我有一个未格式化的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
有没有更好的方法从未格式化的文件中读取可变长度的字符串?
答案 0 :(得分:0)
我稍微修改了您的示例程序,在 binary 中读取文件。这适用于英特尔的编译器; 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
其输出
测试字符串
另一个较长的测试字符串
现在您已知道行长, trim()不再是必需的了。只需使用
write(6,*) line(1:recl_at_start)
这也可以防止你添加"更短的测试字符串"对数据。