在旧版Fortran中读取包含字符的文本文件
在将遗留Fortran代码包装到R中的项目中,文本文件由子程序“rfort”读取。子例程的工作简化版本如下所示:在旧版Fortran中读取包含字符的文本文件,fortran,character,fortran77,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='UNK
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”)
而子例程(在MacOS 10.11.6、R 3.5.0上)可以使用
也可以在R中使用
dyn.load("rfort.so")
运行时不会出错
.Fortran("rfort")
奇怪的是,它只读取“RESULT.DAT”测试的整数列。不管我怎么做,字符列都被忽略了。同样的代码作为一个独立的Fortran程序(使用gfortran 6.1.0编译)也能正常工作,因此我怀疑它与格式有关。然而,我已经束手无策,所以任何帮助都是非常感谢的 我认为读取格式中的8X应该是4X。让我们看一下第一个输入行(我添加了列号): 格式为
8X、2I8、A6
。我们跳过第1-8列,从第9-16列开始读取第一个整数,即b395bbbbb
,从第17-24列开始读取第二个整数1232bb10
。如您所见,部分字符数据被读取为第二个整数。默认值BLANK='NULL'表示忽略嵌入的空格(我假设您没有使用FORTRAN 66编译器!)
我不知道你为什么说它似乎和格弗特兰一起工作。我也不知道为什么根据调用子例程的方式,结果会有所不同。在您的示例中,您似乎希望输出文件由TEST.DAT的最后3列组成,但输出不是您期望看到的。 您有两种选择:1)更改TEST.DAT中的间距以匹配format语句,或2)更改format语句以匹配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”读入名称(10)。太棒了,没错,但不是你所期望的!然后在打印输出时,数字默认为右对齐,而字符默认为左对齐,因此RESULTS.DAT中的最后两列在打印时没有空格:
RESULTS.DAT (line 10) with spacing illustrated:
| | | |
123456781234567812345678123456
726 12931078d
我的建议是:改变你的阅读格式,让它更加宽容和灵活。只需将1020
说明符替换为*
,这意味着行中的每个项目(逗号或空格分隔)形成一个序列,该序列将传输到I/O列表中的相应变量中。这称为列表定向的
格式说明符。请注意,由于行号成为输入列表的一部分,因此需要定义一个整数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)
我觉得
8X
很可能是正确的:输入文本数据的前四列被markdown解析器吞没。特别是代码和标签的缩进。谢谢您的输入,很抱歉造成混淆!我还认为8X
是正确的。“1”由七个空格开头,“10”由六个空格开头,以此类推。第一个空格确实被吞没了。实际上我同意史蒂夫的观点,读写都是8x应该是4x。然后输入和输出的间隔相同,只是输出没有行号。但是如果你在阅读中使用*
,就像在我的答案中一样,那么这并不重要。谢谢你的详细答案!然而,降价使间隔变大了。我编辑了“TEST.DAT”,以便它反映原始版本(行计数器有8个空格)。尽管如此,你的建议,使格式更宽容不起作用,至少在我的系统。R崩溃了,只写了“RESULT.DAT”中的第一行。@Nils崩溃可能与R有关?与gfortran和ifort在这里运行良好。write语句是否仍放在do循环中?如果不起作用,请尝试显式格式。我现在使用读取格式字符串尝试显式格式,如1020格式(8X,I8,I8,1X,A6)
。似乎只读取字符串的第一个字符,因此使用1X
时,名称列会出现,但只显示第一个字符(在本例中为“1”)。使用2X
将显示第二个字符,依此类推。这肯定是一个特定于R的问题,但我仍然不知道如何解决它。
RESULTS.DAT (line 10) with spacing illustrated:
| | | |
123456781234567812345678123456
726 12931078d
read(8, *) dummy_val, IX(i), IY(i), NAME(i)
write(9, "(4x,I8,I8,1x,A6)") IX(i), IY(i), NAME(i)