Convert integers to strings to create output filenames at run time

148,138

Solution 1

you can write to a unit, but you can also write to a string

program foo
    character(len=1024) :: filename

    write (filename, "(A5,I2)") "hello", 10

    print *, trim(filename)
end program

Please note (this is the second trick I was talking about) that you can also build a format string programmatically.

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

Solution 2

A much easier solution 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

Solution 3

Well here is a simple function which will return the left justified string version of an integer:

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

And here is a test code:

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

Solution 4

I already showed this elsewhere on SO (How to use a variable in the format specifier statement? , not an exact duplicate IMHO), but I think it is worthwhile to place it here. It is possible to use the techniques from other answers for this question to make a simple function

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

which you can use after without worrying about trimming and left-adjusting and without writing to a temporary variable:

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

It requires Fortran 2003 because of the allocatable string.

Solution 5

For a shorten version. If all the indices are smaller than 10, then use the following:

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

For a general version:

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

That's all.

Share:
148,138
Alasdair
Author by

Alasdair

Pythonista/Djangonaut

Updated on July 09, 2022

Comments

  • Alasdair
    Alasdair almost 2 years

    I have a program in Fortran that saves the results to a file. At the moment I open the file using

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

    However, I now want to run a loop, and save the results of each iteration to the files 'Output1.TXT', 'Output2.TXT', 'Output3.TXT', and so on.

    Is there an easy way in Fortran to constuct filenames from the loop counter i?

  • F'x
    F'x over 14 years
    Two comments: - you don't have to discriminate on the value of I; the format (I0) will output an integer without any space; also, if you want a fixed width and padding with zeroes (like "output001.txt"), you need to used (I0.3) - the format (A5I2) is not valid Fortran according to any norm, as format specifiers are to be separated by commas: (A5,I2)
  • Stefano Borini
    Stefano Borini over 14 years
    Well, it was for educational purposes, not intended to be the solution. In general I use the padding zeros (as it sorts nicely), but the I0 thingie I didn't know about. Thanks!! (fixed the commas, I think my style was the old one, still accepted)
  • High Performance Mark
    High Performance Mark almost 12 years
    This is a very bad answer. As the accepted answer already shows Fortran provides a mechanism for writing the value of an integer into a character variable; all this fiddling around with encoding and decoding character indices is a horrid hack which serves no useful purpose.
  • gluuke
    gluuke over 10 years
    @F'x thanks for the comment, really useful. Indeed even trim won't work if the number k of digits is not equal to "(Ik)" in the format, so just use "(I0)" so that one doesn't need to adapt the format.
  • ryanjdillon
    ryanjdillon about 10 years
    may just be my compiler, but i was needed to declare a character variable for the output string written to (i.e. character(5) x1). thanks!
  • francescalus
    francescalus almost 9 years
    Using I0 as the edit descriptor would be much simpler: write(filename, '("path/to/file/", I0, ".dat")') i. This is mentioned previously in this question only in comments, so perhaps could be added.
  • fronthem
    fronthem almost 9 years
    Thank you @francescalus, I didn't notice that comment. Then left my answer to be an alternative solution. it may be useful in some case.
  • Osman Mamun
    Osman Mamun almost 9 years
    There should be no comma after after the closing parentheses in write statement. (( write(charI,"(A)") i )) Thanks, I am using this suggestion.
  • PVitt
    PVitt about 8 years
    @HighPerformanceMark Regarding his name, this code looks quite reasonable.
  • kayneo
    kayneo over 7 years
    The default is no comma, but I found it works well if the additional comma added, similar as ((print *, i))
  • Manuel Pena
    Manuel Pena over 5 years
    There is not A0 as the counterpart of I0, right? (meaning a character string with any padding)
  • Jean-Claude Arbaut
    Jean-Claude Arbaut over 3 years
    @ManuelPena "w shall be zero or positive for the I, B, O, Z, D, E, EN, ES, EX, F, and G edit descriptors. w shall be positive for all other edit descriptors." (Fortran 2018, where w is the width parameter). However, the width is not mandatory for the A edit descriptor, and if omitted, the length of the character string is used instead. But bear in mind that this length includes any trailing space: if you want to remove them from the output, use the A edit descriptor (without length parameter) and pass trim(s) instead of s. You may also want to adjustl.