Преобразование целых чисел в строки для создания выходных имен файлов во время выполнения - PullRequest
41 голосов
/ 12 августа 2009

У меня есть программа на Фортране, которая сохраняет результаты в файл. На данный момент я открываю файл, используя

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

Однако теперь я хочу запустить цикл и сохранить результаты каждой итерации в файлы 'Output1.TXT', 'Output2.TXT', 'Output3.TXT' и т. Д.

Есть ли в Фортране простой способ создания имен файлов из счетчика циклов i?

Ответы [ 9 ]

47 голосов
/ 12 августа 2009

вы можете записать в единицу, но вы также можете записать в строку

program foo
    character(len=1024) :: filename

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

    print *, trim(filename)
end program

Обратите внимание (это второй трюк, о котором я говорил), что вы также можете программно построить строку формата.

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
17 голосов
/ 29 апреля 2011

гораздо более простое решение ИМХО ...................

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
8 голосов
/ 08 мая 2013

Хорошо, вот простая функция, которая будет возвращать левую выровненную строковую версию целого числа:

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

А вот и тестовый код:

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
5 голосов
/ 24 июня 2015

Я уже показывал это в другом месте на SO ( Как использовать переменную в операторе спецификатора формата? , а не в точном дубликате ИМХО), но я думаю, что стоит разместить его здесь. Можно использовать методы из других ответов на этот вопрос, чтобы сделать простую функцию

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

, который вы можете использовать после, не беспокоясь об обрезке и подстройке влево и не записывая во временную переменную:

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

Требуется Fortran 2003 из-за выделяемой строки.

2 голосов
/ 19 ноября 2014

Для укороченной версии. Если все индексы меньше 10, используйте следующее:

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

Для общей версии:

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

Вот и все.

0 голосов
/ 28 апреля 2018

Попробуйте следующее:

    ....
    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
    ....

Где "..." означает другой соответствующий код для вашей цели.

0 голосов
/ 06 мая 2016

Чтобы преобразовать целое число в строку:

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
0 голосов
/ 24 июня 2015

Я уже пробовал @Alejandro и @ user2361779, но это дает мне неудовлетворенный результат, такой как file 1.txt или file1 .txt вместо file1.txt. Однако я нахожу лучшее решение:

...
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))
...

Пояснение:

например. набор i = 10 и 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

Я думаю, что это простейшее решение, которое дает вам имя файла с динамической длиной без каких-либо устаревших пробелов от целочисленного до строкового процесса преобразования.

0 голосов
/ 20 января 2011

Вот мой подпрограммный подход к этой проблеме. он преобразует целое число в диапазоне 0: 9999 как символ. Например, INTEGER 123 превращается в символ 0123. Надеюсь, это поможет.

P.S. - извините за комментарии; они имеют смысл на румынском языке: 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
...