使用fortran覆盖文件

时间:2016-07-04 03:38:00

标签: fortran fortran90 overwrite

我正在使用Fortran 90程序来编写文件。该文件的第一行应该表示剩余文件中的行数。当满足某个标准并且无法事先确定时,该程序将编写该文件。基本上,我只知道运行结束后的总行数。

我想以下列方式进行:

1)打开文件并在第一行写一些文字说“ Hello

2)根据需要在文件中写入行,并为行数保留计数器

3)一旦运行结束并且在关闭文件之前,将第一行字符串(“ Hello ”)替换为计数器

问题出在第3步。我不知道如何更换第一行。

我能想到的另一个选择是写入2个文件。首先,在没有计数器的情况下写上面的文件。运行结束后,关闭文件并写入另一个文件,这次,我知道计数器的值。

我相信有一种方法可以继续第一种方法。有人可以帮帮我吗?

2 个答案:

答案 0 :(得分:3)

Fortran支持三种形式的文件访问--DIRECT,STREAM(F2003 +)和SEQUENTIAL。 DIRECT和STREAM访问都支持能够重写文件的早期部分,SEQUENTIAL访问不支持(重写到先前的记录会在重写的记录中截断文件)。

通过直接访问,文件中的所有记录长度相同。任何输入/输出语句都可以[必须]访问任意记录,只需在语句中指定相关的记录号即可。但请注意,直接访问文件的典型磁盘格式可能与您对#34;行"的文件概念不符。

使用格式化流访问,可以使用INQUIRE语句捕获文件中的当前位置,然后稍后的输入/输出语句可以使用POS说明符在该位置开始数据传输。格式化流访问文件的典型磁盘格式通常与人们对带有行的文本文件的期望值相匹配。

您可能想要访问流。两种方法的示例如下所示。

直接访问:

PROGRAM direct
  IMPLICIT NONE

  INTEGER :: unit
  REAL :: r
  INTEGER :: line

  OPEN( NEWUNIT=unit,  &
      FILE='direct.txt',  &
      STATUS='REPLACE',  &
      ACCESS='DIRECT',  &
      RECL=15,  &      ! The fixed record length.
      FORM='FORMATTED' )

  CALL RANDOM_SEED()

  ! No need to write records in order - we just leave off 
  ! writing the first record until the end.

  line = 0
  DO
    CALL RANDOM_NUMBER(r)
    IF (r < 0.05) EXIT

    line = line + 1
    PRINT "('Writing line ',I0)", line
    ! All the "data" records are offset by one, to allow the 
    ! first record to record the line count.
    WRITE (unit, "('line ',I10)", REC=line+1) line
  END DO

  ! Now update the first record with the number of following "lines".
  WRITE (unit, "(I10)", REC=1) line

  CLOSE(unit)
END PROGRAM direct

流访问:

PROGRAM stream
  IMPLICIT NONE

  INTEGER :: unit
  REAL :: r
  INTEGER :: line
  INTEGER :: pos

  OPEN( NEWUNIT=unit,  &
      FILE='stream.txt',  &
      STATUS='REPLACE',  &
      ACCESS='STREAM',  &
      POSITION='REWIND',  &
      FORM='FORMATTED' )

  CALL RANDOM_SEED()

  ! Remember where we are.  In this case, the position 
  ! is the first file storage unit in the file, but 
  ! it doesn't have to be.
  INQUIRE(unit, POS=pos)

  ! Leave some space in the file for later overwriting 
  ! with the number of lines.  We'll stick the number 
  ! zero in there for now.
  WRITE (unit, "(I10)") 0

  ! Write out the varying number of lines.
  line = 0
  DO
    CALL RANDOM_NUMBER(r)
    IF (r < 0.05) EXIT

    line = line + 1
    PRINT "('Writing line ',I0)", line
    WRITE (unit, "('line ',I10)") line
  END DO

  ! Now update the space at the start with the number of following "lines".
  WRITE (unit, "(I10)", POS=pos) line

  CLOSE(unit)
END PROGRAM stream

答案 1 :(得分:2)

返回顺序访问文件很棘手,因为行的长度可能不同。如果你改变一行的长度,就必须把所有东西都移到后面。

我建议在计算行数时将输出写入临时文件。然后,完成后,回滚暂存文件,将行数写入输出文件,并将临时文件的内容复制到该输出文件。

这就是我的所作所为:

program var_file
    implicit none
    character(len=*), parameter :: filename = 'delme.dat'
    integer :: n, io_stat
    character(len=300) :: line

    open(unit=200, status='SCRATCH', action="READWRITE")

    n = 0

    do
        read(*, '(A)') line
        if (len_trim(line) == 0) exit  ! Empty line -> finished
        n = n + 1
        write(200, '(A)') trim(line)
    end do

    rewind(200)

    open(unit=100, file=filename, status="unknown", action="write")
    write(100, '(I0)') n

    do
        read(200, '(A)', iostat=io_stat) line
        if (io_stat /= 0) exit
        write(100, '(A)') trim(line)
    end do

    close(200)
    close(100)

end program var_file
相关问题