2016-07-04 11 views
1

Я использую программу Fortran 90, которая записывает файл. Первая строка этого файла должна указывать количество строк в оставшемся файле. Файл записывается программой, когда выполняется определенный критерий и который не может быть определен заранее. В принципе, я буду знать общее количество строк только после завершения прогона.перезаписать файл, используя fortran

Я хочу сделать это следующим образом:

1) открыть файл и написать первую строку с текстом сказать, «Hello»

2) Написать строки в файле как желательно и сохранить счетчик для количества строк.

3) После того, как запуск закончился, и как раз перед закрытием файла, заменить первую строку строки («Hello») с счетчиком.

Проблема заключается в шаге 3. Я не знаю, как заменить первую строку.

Другим вариантом, о котором я могу думать, является запись в 2 файла. Сначала напишите файл, как указано выше, без счетчика. Как только прогон закончен, закройте файл и напишите другой файл, и на этот раз я знаю значение счетчика.

Я считаю, что есть способ приступить к первому подходу. Может кто-нибудь, пожалуйста, помогите мне с этим?

ответ

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 
+0

Спасибо за подробный ответ и программы. Это был мой план резервного копирования. Вы сохранили мое время, чтобы написать код для перезаписи файла. :) –

+0

Так я бы это сделал. Я не гарантирую, что нет лучшего, о котором я не знаю. – chw21

3

Fortran поддерживает три формы доступа к файлам - прямой, STREAM (F2003 +) и последовательна. Поддержка доступа DIRECT и STREAM позволяет переписывать предыдущие части файла, доступ SEQUENTIAL не выполняется (перезапись на более раннюю запись обрезает файл в перезаписываемой записи).

С прямым доступом все записи в файле имеют одинаковую длину. Любая запись может быть [должна быть доступна] любым оператором ввода/вывода, просто указав соответствующий номер записи в инструкции. Обратите внимание, однако, что типичный формат диска файла прямого доступа может не соответствовать вашей идее файла с «строками».

С форматированным доступом к потоку текущая позиция в файле может быть записана с использованием инструкции 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 
+0

Спасибо за информацию. Опция «Стрим» - это то, как я должен идти. По-видимому, мой компилятор не поддерживает Access = stream. –

+1

Я пропустил тег Fortran 90. Stream - это функция Fortran 2003. – IanH

+0

Многие современные компиляторы Fortran теперь поддерживают 2003 год, в том числе «STREAM», поэтому это ценный ответ, даже если он не работает в этом конкретном случае. Могу ли я предложить, однако, сделать более ясным в самом ответе, что это работает только для компиляторов, совместимых с 2003 годом. – chw21

Смежные вопросы