我一直负责编写Fortran 95的程序,将从文件中读取字符输入,然后(先从)只是吐回来了一次。 棘手的部分是,输入的这些线是不同长度(未给出最大长度)的并且可以存在任何数量的在文件中的行。
我用
do
read( 1, *, iostat = IO ) DNA ! reads to EOF -- GOOD!!
if ( IO < 0 ) exit ! if EOF is reached, exit do
I = I + 1
NumRec = I ! used later for total no. of records
allocate( Seq(I) )
Seq(I) = DNA
print*, I, Seq(I)
X = Len_Trim( Seq(I) ) ! length of individual sequence
print*, 'Sequence size: ', X
print*
end do
但是,我最初的语句列表
character(100), dimension(:), allocatable :: Seq
character(100) DNA
和合适的整数等。
我猜我问的是,如果有什么办法不列出在一审的字符串的大小。 说我有DNA的字符串,它是200多个字符,然后又是只有25岁,是有办法,程序可以只是读什么就有什么,而不是需要包括所有附加的空白? 可以这样无需使用做len_trim
,因为它不能在声明语句中引用?
逐步阅读的Fortran 95的记录,使用非推进输入。 例如:
CHARACTER(10) :: buffer
INTEGER :: size
READ (unit, "(A)", ADVANCE='NO', SIZE=size, EOR=10, END=20) buffer
将读取最多10个字符价值(缓冲区长度)的每个被调用时。 文件位置将只提前一旦整个记录已经通过一系列的一个或多个非推进读取读取下一个记录(下一行)。
除非的文件状态的端部,所述size
可变的将与读入的字符的实际数量来定义buffer
在每次执行读取语句的时间。
在EOR
和END
和说明符使用时记录或文件条件端的端分别发生来控制执行流程(执行将跳转到适当标记的语句)。 您也可以使用IOSTAT
符来检测这些条件,但具体的负值使用的两个条件是依赖于处理器。
您能不能总结size
特定记录内制定出具体的记录的长度。
总结这样的非推进的循环中适当地检测文件和记录结束的读取结束,你有增量阅读部分。
在Fortran 95中,对于本地字符可变长度规范必须是一个规范表达式 - 本质上可以在此之前,包含该变量的声明的范围的第一个可执行语句被安全地求值的表达式。 常量表示最简单的情况,但是在过程的规范表达可能涉及过程的伪参数,除其他事项。
读取任意长度的整个记录随后的多阶段过程:
- 通过增量读取使用一系列确定当前记录的长度。 这些增量读取特定记录结束时的记录条件的结束时发生,此时的文件位置将已经转移到下一个记录。
-
Backspace
将文件恢复到感兴趣的记录。 - 调用过程,传递当前记录的长度为伪参数。 内部的程序有一个字符变量,其长度由伪参数给出。
- 里面调用程序,使用正常推进输入读取当前记录到该字符变量。
- 开展进一步的处理对字符变量!
请注意,每个记录最终被读两次 - 一次,以确定它的长度,所述第二实际数据读入正确“lengthed”字符变量。
替代方法存在使用可分配的(或自动)长度的一个的字符阵列。 总体战略是一致的。 看代码的一个例子共同ISO_VARYING_STRING实现获取程序。
Fortran 2003的介绍推迟长度字符变量,这可以通过任意表达式指定它们的长度在一个分配的语句,或者对于分配变量,由右侧的在一个赋值语句的长度。 这(与其它“分配”的增强结合)允许逐行读确定记录长度也建立保持该记录的内容的字符变量。 你的上司需要把他的Fortran语言环境是最新的。
这里的(任选地修整),用于Fortran 2003的,它设定了输入字符串的准确长度的可分配的串(内联)的函数,或者返回.FALSE。 如果文件结束
function ReadLine(aunit, InLine, trimmed) result(OK)
integer, intent(IN) :: aunit
character(LEN=:), allocatable, optional :: InLine
logical, intent(in), optional :: trimmed
integer, parameter :: line_buf_len= 1024*4
character(LEN=line_buf_len) :: InS
logical :: OK, set
integer status, size
OK = .false.
set = .true.
do
read (aunit,'(a)',advance='NO',iostat=status, size=size) InS
OK = .not. IS_IOSTAT_END(status)
if (.not. OK) return
if (present(InLine)) then
if (set) then
InLine = InS(1:size)
set=.false.
else
InLine = InLine // InS(1:size)
end if
end if
if (IS_IOSTAT_EOR(status)) exit
end do
if (present(trimmed) .and. present(InLine)) then
if (trimmed) InLine = trim(adjustl(InLine))
end if
end function ReadLine
例如做所有东西线与单元中的文件“aunit”吗
character(LEN=:), allocatable :: InLine
do while (ReadLine(aunit, InLine))
[.. something with InLine]
end do
我已经使用了下面。 让我知道,如果它比你的更好或更坏。
!::::::::::::::::::::: SUBROUTINE OR FUNCTION :::::::::::::::::::::::::::::::::::::::
!__________________ SUBROUTINE lineread(filno,cargout,ios) __________________________
subroutine lineread(filno,cargout,ios)
Use reallocate,ErrorMsg,SumStr1,ChCount
! this subroutine reads
! 1. following row in a file except a blank line or the line begins with a !#*
! 2. the part of the string until first !#*-sign is found or to end of string
!
! input Arguments:
! filno (integer) input file number
!
! output Arguments:
! cargout (character) output chArActer string, converted so that all unecessay spaces/tabs/control characters removed.
implicit none
integer,intent(in)::filno
character*(*),intent(out)::cargout
integer,intent(out)::ios
integer::nlen=0,i,ip,ich,isp,nsp,size
character*11,parameter::sep='=,;()[]{}*~'
character::ch,temp*100
character,pointer::crad(:)
nullify(crad)
cargout=''; nlen=0; isp=0; nsp=0; ich=-1; ios=0
Do While(ios/=-1) !The eof() isn't standard Fortran.
READ(filno,"(A)",ADVANCE='NO',SIZE=size,iostat=ios,ERR=9,END=9)ch ! start reading file
! read(filno,*,iostat=ios,err=9)ch;
if(size>0.and.ios>=0)then
ich=iachar(ch)
else
READ(filno,"(A)",ADVANCE='no',SIZE=size,iostat=ios,EOR=9); if(nlen>0)exit
end if
if(ich<=32)then ! tab(9) or space(32) character
if(nlen>0)then
if(isp==2)then
isp=0;
else
isp=1;
end if
eend if; cycle;
elseif(ich==33.or.ich==35.or.ich==38)then !if char is comment !# or continue sign &
READ(filno,"(A)",ADVANCE='yes',SIZE=size,iostat=ios,EOR=9)ch; if(nlen>0.and.ich/=38)exit;
else
ip=scan(ch,sep);
if(isp==1.and.ip==0)then; nlen=nlen+1; crad=>reallocate(crad,nlen); nsp=nsp+1; endif
nlen=nlen+1; crad=>reallocate(crad,nlen); crad(nlen)=ch;
isp=0; if(ip==1)isp=2;
end if
end do
9 if(size*ios>0)call ErrorMsg('Met error in reading file in [lineread]',-1)
! ios<0: Indicating an end-of-file or end-of-record condition occurred.
if(nlen==0)return
!write(6,'(a,l)')SumStr1(crad),eof(filno)
!do i=1,nlen-1; write(6,'(a,$)')crad(i:i); end do; if(nlen>0)write(6,'(a)')crad(i:i)
cargout=SumStr1(crad)
nsp=nsp+1; i=ChCount(SumStr1(crad),' ',',')+1;
if(len(cargout)<nlen)then
call ErrorMsg(SumStr1(crad)// " is too long!",-1)
!elseif(i/=nsp.and.nlen>=0)then
! call ErrorMsg(SumStr1(crad)// " has unrecognizable data number!",-1)
end if
end subroutine lineread
我使用Fortran 90的做到这一点:
X = Len_Trim( Seq(I) ) ! length of individual sequence
write(*,'(a<X>)') Seq(I)(1:X)
你可以简单地声明序列是一个大的字符串,然后修剪它作为你写出来。 我不知道这个解决方案如何犹太是,但它肯定适合我的目的。 我知道有些编译器不支持“可变格式表达式”,但也有不同的解决方法做同样的事情几乎一样简单。
GNU Fortran的变量表达式的解决方法。