读取旧版Fortran中带有字符的文本文件

时间:2019-03-09 13:28:53

标签: fortran character fortran77

在将旧版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 个答案:

答案 0 :(得分:1)

我认为您的READ格式的8X应该是4X。让我们看一下第一行输入(我已经添加了列号):

         1         2
1234567890123456789012345
   1     395    1232 1084

格式为8X,2I8,A6。我们跳过第1-8列,并开始从第9-16列读取第一个整数,b395bbbb,从第17-24列读取第二个整数1232bb10。如您所见,部分字符数据被读取为第二个整数。默认值BLANK ='NULL'意味着嵌入的空格将被忽略(我假设您未使用FORTRAN 66编译器!)

为什么您说它似乎可以与gfortran一起使用,我不知道。我也不知道为什么根据调用子例程的方式结果会有所不同。

答案 1 :(得分:0)

在您的示例中,您似乎希望输出文件由TEST.DAT的最后3列组成,但是输出不是您期望看到的。 您有两种选择:1)更改TEST.DAT中的间距以匹配格式语句,或2)更改格式语句以匹配TEST.DAT中的间距。

让我们看看您的格式声明。 1020格式表示跳过前8列,从接下来的16列中读取2个整数类型(每个int为8列),然后从接下来的6列中读取字符类型。例如,TEST.DAT的第10行的内容如下:

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指示符替换为*,这意味着该行上的每个项目(以逗号或空格分隔)形成一个序列,该序列将被传输到I / O列表中的相应变量中。这称为list-directed格式说明符。请注意,由于行号已成为输入列表的一部分,因此需要定义一个整数integer dummy_val(在子例程的顶部),然后可以忽略该整数。现在使用以下命令阅读每一行:

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

您可以对写入语句执行相同的操作:write(9,*), IX(i), IY(i), NAME(i),它将使用合理的默认字段宽度并确保I / O列表中每个项目之间都存在空白。如果要对输出的格式进行更多控制,请继续使用format语句,但要对其进行更改,以确保在每个项目之间放置一定数量的空格:

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