带有ascii数据的FORTRAN代码

时间:2015-08-21 14:00:32

标签: fortran

我有一个ASCII格式的数据(.txt文件),其中日期是以一年一格(即.9900601)的格式列中给出的。我想将此列分为三列,每列包含年,月和日期。谁能告诉你如何在Fortran中做到这一点?我的数据文件和代码如下:

数据表 19480501 -1
19480502 -1
19480503 2
19480504 -1
19480505 2
19480506 -1
19480507 -1
19480508 -1
19480509 -1
19480510 -1
19480511 -1
19480512 2
  。 。   。

代码:

program ascii_read    
!real(kind=8):: rain(np)    
real,allocatable:: rain(:)    
integer::np=15739  
!integer(kind=8)::day(np)  
integer,allocatable::day(:)  
character(len = 80)::firstline  
integer::i,j  
integer,allocatable:: year(:)  
allocate (year(np-1))  
allocate (rain(np))  
allocate (day(np))  
open(1243,file="11700.text",status="unknown")
open(12,file="11700_output.text",status="unknown")
read(1243,*)firstline  

do i=2,np  
read(1243,1111)day(i),rain(i)  
end do  
1111 Format(i6,F5.2)  
write(*,*)day    
do j = 1,np-1  
year(j)=day(j)   
end do   
write(*,fmt='(i4)')year    
1 format(I4)  
!write(*,*)year  
return    
stop   
end program    

这使得一年中只有一年分开,而不是一个月和一天。知道如何将月份和日期与此数据文件分开吗?

3 个答案:

答案 0 :(得分:3)

您可以使用格式化的读取来明确地提取每个字段:

integer year,month,day,rain

...

read(1234,'(i4,i2,i2,i3)')year,month,day,rain

在您的代码中,您使用i6,因此day(i)包含“194805”之类的内容,然后从该行的其余部分读取rain(i)(即“{1}}的最后两位数字” date“整数空格和另一个整数”。我不知道f5.2格式对此做了什么,但它不是你想要的那样)

答案 1 :(得分:2)

您必须分析输入和所需输出之间的关系,然后实现关系;这就是编程的工作原理。你必须首先知道一种方法来自己解决问题,然后教电脑如何做到这一点。 对于这个问题,你可以简单地看到前4位代表年份,接下来的2位代表月份,最后2位代表日期。要获得前4个,您将整数除以10000,它只是拒绝最后4个(月和日)。您使用模运算来获取最后四个。并做同样的事情来提取最后两个月的月份。 定义新的数组变量monthdate并将它们分配到与day相同的大小,同时添加一个新的整数变量tmp并将第二个循环更改为:

    do j = 1,np-1
        year(j)=day(j)/10000
        tmp = mod(day(j), 10000)
        month(j) = tmp/100
        date(j) = mod(tmp,100)
    end do

我还建议您使用免费格式阅读。您可以使用固定格式进行写入以对齐数据并使其易于可视化。 开始时去寻找现代编程。在代码中,Litteral数字不是一个好主意,因此对文件ID使用命名常量。确保在不再需要文件时关闭文件。当您打开文件进行阅读时,请使用status ='old',您希望文件存在,或者您希望程序停止并显示相应的消息。使用格式时,请使用格式参数readwrite而不是格式语句,例如使用名称arg fmt,就像在某些地方一样。这使调试变得容易。所以你的程序看起来像这样。

program ascii_read
    !real(kind=8):: rain(np)
    integer, parameter :: inputId = 1243
    integer, parameter :: outputId = 12
    real,allocatable,dimension(:):: rain
    integer::np=12
    !integer(kind=8)::day(np)
    character(len = 80)::firstline
    integer::i,j, tmp
    integer,allocatable,dimension(:):: day, year, month, date

    allocate ( year(np-1), rain(np), day(np), month(np), date(np) )
    open(inputId,file="11700.text",status="old")
    open(outputId,file="11700_output.text",status="unknown")
    read(inputId,*)firstline  

    do i=2,np  
        read(inputId,*)day(i),rain(i)
    end do
    close(inputId)

    write(*,*) day
    do j = 1,np-1
        year(j)=day(j)/10000
        tmp = mod(day(j), 10000)
        month(j) = tmp/100
        date(j) = mod(tmp,100)
        ! just to see what we get.
        write(*, *) day(j), year(j), month(j), date(j)
    end do
    !write(*,fmt='(i4)')year
    !1 format(I4)
    !write(*,*)year

    return
    stop
end program

感谢IanH的评论,最新版本的fortran包含了一个newunit选项,用于处理程序员的IO单元号。这使您无需为单元号定义命名常量。如果您不使用最新版本(有些公司不经常升级),可以在fortranwiki中使用。

答案 2 :(得分:1)

A" hybrid"另外两个答案的方法是首先将数据读入缓冲区,然后将其拆分为整数

collection-repeat

这里,列表导向的I / O用于在第一列之前跳过可能的空格,而整数则根据宽度提取。此外,注释行以"#"开头。例如,在第一个读取语句之后插入collection-repeat可以跳过(如果有的话)。