Читать текстовый файл с символами в старом Фортране - PullRequest
0 голосов
/ 09 марта 2019

В проекте, обертывающем старый код Fortran в R, текстовый файл читается подпрограммой "rfort".Рабочая упрощенная версия подпрограммы выглядит следующим образом:

  SUBROUTINE rfort()
  implicit none

  INTEGER I,IX,IY
  DIMENSION IX(10),IY(10)
  CHARACTER*6 NAME(10)

  OPEN(UNIT=8,FILE='TEST.DAT',STATUS='OLD')
  OPEN(UNIT=9,FILE='RESULT.DAT',STATUS='UNKNOWN')

  DO I=1,10
  READ(8,1020)IX(I),IY(I),NAME(I)
1020      FORMAT(8X,2I8,A6)
  WRITE(9,1030)IX(I),IY(I),NAME(I)      
1030      FORMAT(8X,2I8,A6)
  ENDDO
  CLOSE (8)
  CLOSE (9)
  END

Текстовый файл ("TEST.DAT") состоит из четырех переменных: идентификатор строки (игнорируется), две целочисленные переменные ("IX"), "IY") и одна символьная переменная ("NAME").

       1     395    1232 1084
       2     415    1242 1024
       3     433    1253 125
       4     409    1204 1256
       5     427    1217 105
       6     446    1226 1253
       7     489    1239 1254
       8     560    1255 1260a
       9     720    1270 1067
      10     726    1293 1078d

В то время как подпрограмма компилируется нормально (в MacOS 10.11.6, R 3.5.0) с

R CMD SHLIB rfort.f

и может также вызываться в R с помощью

dyn.load("rfort.so")

и без ошибок запускается с

.Fortran("rfort")

, странным образом считывает только целочисленные столбцы, как проверено "RESULT.DAT".Столбец символов игнорируется, что бы я ни пытался.Тот же код работает, как и ожидалось, как отдельная Fortran-программа (скомпилированная с gfortran 6.1.0), поэтому я подозреваю, что это как-то связано с форматированием.Тем не менее, я в своем уме, поэтому любая помощь приветствуется!

Ответы [ 2 ]

1 голос
/ 09 марта 2019

Я думаю, что 8X в вашем формате READ должно быть 4X. Давайте посмотрим на первую строку ввода (я добавил номера столбцов):

         1         2
1234567890123456789012345
   1     395    1232 1084

Формат 8X,2I8,A6. Мы пропускаем столбцы 1-8 и начинаем читать первое целое число из столбцов 9-16, которое равно b395bbbb, а второе из столбцов 17-24 1232bb10. Как видите, часть символьных данных читается как второе целое число. Значение по умолчанию BLANK = 'NULL' означает, что встроенные пробелы игнорируются (я предполагаю, что вы не используете компилятор FORTRAN 66!)

Почему вы говорите, что это похоже на работу с гфортраном, я не знаю. Также я не знаю, почему результаты должны отличаться в зависимости от того, как вы вызываете подпрограмму.

0 голосов
/ 09 марта 2019

В вашем примере кажется, что вы хотите, чтобы выходной файл состоял из трех последних столбцов из TEST.DAT, но результат не тот, который вы ожидаете увидеть. У вас есть два варианта: 1) изменить интервал в TEST.DAT, чтобы он соответствовал операторам формата, или 2) изменить операторы формата, чтобы они соответствовали интервалу в TEST.DAT.

Давайте посмотрим на ваши утверждения формата. Формат 1020 говорит, что необходимо пропустить первые 8 столбцов, прочитать 2 целочисленных типа из следующих 16 столбцов (8 столбцов для каждого типа int), а затем тип символов из следующих 6 столбцов. Например, строка 10 из TEST.DAT читается следующим образом:

TEST.DAT (line 10) with spacing illustrated:
       |       |       |     |
123456781234567812345678123456
  10     726    1293 1078d

Как видите, значение «726» считывается в IX (10), но «12393107» читается в IY (10), а «8d» читается в NAME (10). Круто, верно, но не то, что вы ожидали! Затем при выводе на печать числа по умолчанию выровнены по правому краю, а по умолчанию выровнены по левому краю, поэтому последние два столбца в RESULTS.DAT печатаются без пробелов между ними:

RESULTS.DAT (line 10) with spacing illustrated:
       |       |       |     |
123456781234567812345678123456
             726 12931078d    

Вот моя рекомендация: измените свой формат чтения, чтобы он был более щадящим и гибким. Просто замените спецификатор 1020 на *, что означает, что каждый элемент в строке (через запятую или через пробел) образует последовательность, которая будет передана в соответствующую переменную в вашем списке ввода / вывода. Это называется спецификатором формата list-directed. Обратите внимание, что поскольку номер строки становится частью списка ввода, вам необходимо определить целое число integer dummy_val (в верхней части подпрограммы), которое затем можно игнорировать. Теперь прочитайте каждую строку, используя:

read(8, *) dummy_val, IX(i), IY(i), NAME(i)

Вы можете сделать то же самое для своей записи: write(9,*), IX(i), IY(i), NAME(i), которая будет использовать разумную ширину поля по умолчанию и гарантировать, что между каждым элементом в списке ввода / вывода будет пробел. Если вы хотите больше контролировать форматирование выходных данных, продолжайте использовать оператор форматирования, но измените его так, чтобы между каждым элементом гарантированно было определенное количество пробелов:

write(9, "(4x,I8,I8,1x,A6)") IX(i), IY(i), NAME(i)
...