Search code examples
fortran

How to overwrite part of a binary file?


I want to process a binary file and write the results into a new one of the same format.

My code starts by copying the header, and, for each data frame, load/process/output it:

      program main
      use, intrinsic :: iso_fortran_env, only: int32, real32
      implicit none

      integer(kind=int32),dimension(:),allocatable :: header
      real(kind=real32),dimension(:),allocatable :: frame

      integer(kind=int32) nb_frames, frame_sz
      integer i

      allocate(header(256))

      open(unit=1,file='fort.1',access='stream',status='old')
      read(1) header

      frame_sz = header(1)
      nb_frames = header(2)
      allocate(frame(frame_sz))

      open(unit=2,file='fort.2',access='stream',status='new')
      write(2) header

      do i=1,nb_frames
          read(1) frame
C ...     some calculations
          write(2) frame
      enddo

      close(unit=1)

C ... PLACEHOLDER: update a few values in the header of unit #2

      close(unit=2)
      deallocate(header)
      deallocate(frame)

      end

After processing the whole input file I need to update the header in the outputted file. How would you do it?


Solution

  • If an external file has a defined position, the next data transfer statement involving that file starts at the next position. You can position a file at its initial point using the rewind statement:

    rewind(unit)
    write(unit=2, ...) ! Transfer starting from the initial point
    

    In terms of overwriting, the impact of a write to a file positioned at its initial, or other, point depends on the access mode of the external file:

    • a write to a sequentially connected file is liable to be followed by the implicit write of an endfile record
    • records for a directly connected file are overwritten and there's no jeopardy that an endfile record be written
    • file storage units of a stream file are overwritten and records don't exist

    For a sequentially connected file, the effect of an endfile record is to truncate (subsequent records are no longer considered to exist).

    All that's to say: if you have a stream access file, you can (over)write arbitrary file storage units. You needn't even rewind:

    write(unit=2, pos=1, ...)
    

    If you need to write more data at an earlier point in a file, you are out of luck:

    • a direct access file will hit an end-of-record condition
    • a stream access file will overwrite subsequent file storage units