Converte números inteiros em sequências para criar nomes de arquivos de saída em tempo de execução

Eu tenho um programa em Fortran que salva os resultados em um arquivo. No momento eu abro o arquivo usando

OPEN (1, FILE = 'Output.TXT') 

No entanto, agora quero executar um loop e salvar os resultados de cada iteração nos arquivos 'Output1.TXT' , 'Output2.TXT' , 'Output3.TXT' e assim por diante.

Existe uma maneira fácil em Fortran para construir nomes de arquivo do contador de loops?

você pode escrever para uma unidade, mas você também pode gravar em uma string

 program foo character(len=1024) :: filename write (filename, "(A5,I2)") "hello", 10 print *, trim(filename) end program 

Por favor note (este é o segundo truque que eu estava falando) que você também pode construir uma string de formato programaticamente.

 program foo character(len=1024) :: filename character(len=1024) :: format_string integer :: i do i=1, 10 if (i < 10) then format_string = "(A5,I1)" else format_string = "(A5,I2)" endif write (filename,format_string) "hello", i print *, trim(filename) enddo end program 

Uma solução muito mais fácil IMHO ……………….

 character(len=8) :: fmt ! format descriptor fmt = '(I5.5)' ! an integer of width 5 with zeros at the left i1= 59 write (x1,fmt) i1 ! converting integer to string using a 'internal file' filename='output'//trim(x1)//'.dat' ! ====> filename: output00059.dat 

Bem, aqui está uma function simples que retornará a versão de string justificada à esquerda de um inteiro:

 character(len=20) function str(k) ! "Convert an integer to string." integer, intent(in) :: k write (str, *) k str = adjustl(str) end function str 

E aqui está um código de teste:

 program x integer :: i do i=1, 100 open(11, file='Output'//trim(str(i))//'.txt') write (11, *) i close (11) end do end program x 

Eu já mostrei isso em outro lugar em SO ( Como usar uma variável na instrução especificador de formato?, Não uma IMHO duplicada exata), mas acho que vale a pena colocá-lo aqui. É possível usar as técnicas de outras respostas para essa questão para fazer uma function simples

 function itoa(i) result(res) character(:),allocatable :: res integer,intent(in) :: i character(range(i)+2) :: tmp write(tmp,'(i0)') i res = trim(tmp) end function 

que você pode usar depois sem se preocupar com o ajuste e ajuste à esquerda e sem gravar em uma variável temporária:

 OPEN(1, FILE = 'Output'//itoa(i)//'.TXT') 

Requer o Fortran 2003 por causa da string alocável.

Para uma versão abreviada. Se todos os índices forem menores que 10, use o seguinte:

 do i=0,9 fid=100+i fname='OUTPUT'//NCHAR(i+48) //'.txt' open(fid, file=fname) !.... end do 

Para uma versão geral:

 character(len=5) :: charI do i = 0,100 fid = 100 + i write(charI,"(A)"), i fname ='OUTPUT' // trim(charI) // '.txt' open(fid, file=fname) end do 

Isso é tudo.

Tente o seguinte:

  .... character(len=30) :: filename ! length depends on expected names integer :: inuit .... do i=1,n write(filename,'("output",i0,".txt")') i open(newunit=iunit,file=filename,...) .... close(iunit) enddo .... 

Onde “…” significa outro código apropriado para o seu propósito.

Eu já tentei @ Alejandro e @ user2361779 mas me dá um resultado insatisfeito como file 1.txt ou file1 .txt vez de file1.txt . No entanto, eu acho a melhor solução:

 ... integer :: i character(len=5) :: char_i ! use your maximum expected len character(len=32) :: filename write(char_i, '(I5)') i ! convert integer to char write(filename, '("path/to/file/", A, ".dat")') trim(adjustl(char_i)) ... 

Explicação:

por exemplo, defina i = 10 e write(char_i, '(I5)') i

 char_i gives " 10" ! this is original value of char_i adjustl(char_i) gives "10 " ! adjust char_i to the left trim(adjustl(char_i)) gives "10" ! adjust char_i to the left then remove blank space on the right 

Eu acho que esta é uma solução mais simples que lhe dá um nome de arquivo de comprimento dynamic sem espaços em branco legados do processo de conversão de inteiro para string.

Para converter um inteiro em uma string:

 integer :: i character* :: s if (i.LE.9) then s=char(48+i) else if (i.GE.10) then s=char(48+(i/10))// char(48-10*(i/10)+i) endif 

Aqui está a minha abordagem de sub-rotina para este problema. Ele transforma um inteiro no intervalo 0: 9999 como um caractere. Por exemplo, o INTEGER 123 é transformado no caractere 0123. Espero que ajude.

PS – desculpe pelos comentários; eles fazem sentido em romeno: P

  subroutine nume_fisier (i,filename_tot) implicit none integer :: i integer :: integer_zeci,rest_zeci,integer_sute,rest_sute,integer_mii,rest_mii character(1) :: filename1,filename2,filename3,filename4 character(4) :: filename_tot ! Subrutina ce transforma un INTEGER de la 0 la 9999 in o serie de CARACTERE cu acelasi numar ! pentru a fi folosite in numerotarea si denumirea fisierelor de rezultate. if(i<=9) then filename1=char(48+0) filename2=char(48+0) filename3=char(48+0) filename4=char(48+i) elseif(i>=10.and.i<=99) then integer_zeci=int(i/10) rest_zeci=mod(i,10) filename1=char(48+0) filename2=char(48+0) filename3=char(48+integer_zeci) filename4=char(48+rest_zeci) elseif(i>=100.and.i<=999) then integer_sute=int(i/100) rest_sute=mod(i,100) integer_zeci=int(rest_sute/10) rest_zeci=mod(rest_sute,10) filename1=char(48+0) filename2=char(48+integer_sute) filename3=char(48+integer_zeci) filename4=char(48+rest_zeci) elseif(i>=1000.and.i<=9999) then integer_mii=int(i/1000) rest_mii=mod(i,1000) integer_sute=int(rest_mii/100) rest_sute=mod(rest_mii,100) integer_zeci=int(rest_sute/10) rest_zeci=mod(rest_sute,10) filename1=char(48+integer_mii) filename2=char(48+integer_sute) filename3=char(48+integer_zeci) filename4=char(48+rest_zeci) endif filename_tot=''//filename1//''//filename2//''//filename3//''//filename4//'' return end subroutine nume_fisier