【问题标题】:Writing specific parts of the file to another file将文件的特定部分写入另一个文件
【发布时间】:2015-09-03 02:01:03
【问题描述】:

我正在编写一个代码来读取具有几个对象的大文件(文件 XYZ)(比如 A、B、C、D、E ......可能还有更多,每个对象都有数百个数据文件)。现在我需要将文件读入 Fortran 并选择一个对象,例如“对象 B”,并将“对象 B”的所有信息写入我使用 fortran 代码创建的新文件中。

每个对象(来自 A-....)都有由头文件和数据数组组成的信息(一个矩阵(i,j),其中 i 因每个文件而异, j=4 )。我必须将标头和数组数据都读入新文件,并且这些对象(A-....)不是按顺序排列的(假设 A 之后可能是 C 或 D)。

我编写了一个小代码,但它似乎不能很好地工作,因为我要么只能输出标头而不能输出数组,要么根本不为对象和代码附加数据文件。

 program trail


   implicit none

    CHARACTER (LEN=5) :: thumb='3C286', SOURCE

    INTEGER :: pair(4), n,io, allocstat


   real, dimension(:,:),allocatable:: a



  CHARACTER (LEN=20) ::  POLCODE, DEC, RA 
  CHARACTER (LEN=40) :: TELESCOPE, NAME_MY, DATA_FILENAME, object , date,  TEXT, HEADER, restfreq,BANDWIDT, TSYS, OBSTIME, ANGLE
  character(len=180) :: Outdat
  character(len=75) :: ra_1, residu, flux, vlafit
  open(2, FILE='trail9.txt',POSITION='APPEND')

do
    open(1, File="column_3C286_iteration1.txt",status='old' )

     read(1,*), SOURCE


 10  if(Source.eq.'OJ287') then

   ! READING THE DATA   

      read(1,'(A40)') DATA_FILENAME
      read(1,'(A40)') TELESCOPE
      read(1,'(A40)') NAME_MY
      read(1,'(A40)') data_filename
      read(1,'(A40)') OBJECT
      read(1,'(A40)') restfreq
      read(1,'(A20)')  polcode
      read(1,'(A40)') angle
      read(1,'(A40)') date
      read(1,'(A40)') bandwidt
      read(1,'(A40)') tsys
      read(1,'(A40)') obstime
      read(1,'(A20)') ra
      read(1,'(A20)') dec
      read(1,'(A40)') text
      read(1,'(A40)')  header
      read(1,'(A180)') OUTDAT
      read(1,"(T2, A3,T30,A4, T50,A6,T67,A6)"),ra_1, residu, flux, vlafit



n=0

  do
    read(1,*,iostat=io) pair
    if (io/=0) exit
    n = n + 1
  end do


allocate(a(n,4),stat=allocstat)

do   i=1,n                                                                                 
    read(1,*)  (a(i,j),j=1,4 )                                              

  enddo 

 if  (index(data_filename,'#')>0 ) then 

!WRITING THE DATA

              write(2,'(A40)')  DATA_FILENAME

             write(2,'(A40)') TELESCOPE
            write(2,'(A40)') NAME_MY
            write(2,'(A40)') data_filename
            write(2,'(A40)') OBJECT
            write(2,'(A40)') restfreq
            write(2,'(A20)')  polcode
            write(2,'(A40)') angle
            write(2,'(A40)') date
            write(2,'(A40)') bandwidt
            write(2,'(A40)') tsys
            write(2,'(A40)') obstime
            write(2,'(A20)') ra
            write(2,'(A20)') dec
            write(2,'(A40)') text
            write(2,'(A40)')  header
                WRITE(2,'(A180)') OUTDAT
 Write(2,"(T2, A3,T30,A4, T50,A6,T67,A6)"),ra_1, residu, flux, vlafit


 do i=1,n

    write(2,"(T1,F10.4: T27,F10.4,T47, F10.4, T63,F10.4, T75,F10.4 )"), (a(i,j), j=1,4)

end do

end do
 end if


end do

end program trail

【问题讨论】:

  • 好吧,我的错。当我在这里加载命令时,我实际上注释掉了它。最初我使用跳转代替 i。使用上面的代码,我最终得到一个空白的输出文件。
  • 嘿,我尝试了上述解决方案,但我最终还是得到了一个空白文件,它仍然没有给出与我预期一致的 n 值
  • 嘿,是的,我的代码包含许多具有相同格式(标题+数据行)的不同对象块。我使用 gfortran 编译器

标签: fortran


【解决方案1】:

请尝试将pair的类型从整数更改为实数并将代码修改为

real :: pair(4)
integer :: i

n = 0
do
    read(1,*,iostat=io) pair
    if (io/=0) exit
    n = n + 1
end do

do i = 1, n + 1
    backspace( 1 )
enddo 

这样,read 语句对包含四个浮点数的行进行计数,并在该行中发现非数字字符(例如 #)时停止读取。另请注意,backspace() 执行了 n+1 次,以便文件指针回到当前数据段的顶部。

虽然不是很确定,但我也认为下面的公开声明

open(1, File="column_3C286_iteration1.txt",status='old' )

如果对应于数据文件,则应该写在最外层的 DO 循环之前。

总而言之,我建议进行以下修改:

real :: pair(4)
integer :: i

open(1, File="column_3C286_iteration1.txt",status='old' )

do
    read(1,*,end=5000), SOURCE     

    if( Source .eq.'OJ287' ) then

        ! read the remaining header and data lines in one block.

        read(1,'(A40)') DATA_FILENAME
        read(1,'(A40)') TELESCOPE
        ...
        read(1,"(T2, A3,T30,A4, T50,A6,T67,A6)"),ra_1, residu, flux, vlafit

        n = 0
        do
            read(1,*,iostat=io) pair
            if (io/=0) exit
            n = n + 1
        end do

        do i = 1, n + 1
            backspace( 1 )
        enddo    

        if ( allocated( a ) ) deallocate( a )
        allocate( a( n, 4 ) )

        do i = 1, n
            read( 1, * ) a( i, 1:4 )
        enddo

        !! write out the obtained data to file 2.
    endif
enddo
5000 continue

编辑

如果我们只是想将一个“header + data”块复制到另一个文件中,那么直接回显块中的所有行而不进行格式化会更直接。例如,程序可能如下所示。

character(200) :: str, field
integer :: ios
real :: dum
open( 10, file="input.dat", status="old" )

do
    read( 10, "(a)", end=5000 ) str

    if ( trim(str) == "OJ287" ) then     !! search for the target block

        print "(a)", trim(str)   !! print the tag

        !! read one block.                                                      
        do
            read( 10, "(a)", end=5000 ) str
            read( str, * ) field     !! get the first field of a line

            if ( field(1:1) == "#" .or. field(1:2) == "ra" ) then

                print "(a)", trim(str)  !! header part
            else
                read( str, *, iostat=ios ) dum   !! test if this line starts with a number
                if ( ios == 0 ) then
                    print "(a)", trim(str)  !! data part                        
                else
                    backspace( 10 )
                    exit
                endif
            endif
        enddo

    endif
enddo
5000 continue

【讨论】:

  • 嗨,我尝试使用上述建议,但最终出现错误 Fortran runtime error: Bad real number in item 1 of list input
  • 嘿伙计,谢谢它运作良好。该错误可能是因为应该包含 read(1,*,iostat=io) 对(4) 而不仅仅是对。谢谢一群朋友。
  • 很高兴听到它有效。顺便说一句,您是否可能尝试使用相同的格式将文件中的选定块(标题+数据行)简单地“复制”到另一个文件中?如果是这样,您可以以更简单的方式执行此操作(如果您对这样的代码感兴趣,请告诉我)。干杯:)
  • 嘿,是的,我正在尝试将标题+数据行从一个文件复制到另一个文件。您能否告诉执行此操作的更简单方法:)。干杯
  • @carltonxavier 我已经更新了简单复制所需块的答案。我一开始以为代码会变得简单很多,但实际上没那么简单……用awk或者python等可能更容易(即,不是Fortran)。
猜你喜欢
  • 1970-01-01
  • 2019-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-10
  • 1970-01-01
  • 2016-08-05
相关资源
最近更新 更多