How to replace C ftell() and fseek() functions in Fortran?

I am translating another musical C program to Fortran. In the MIDI binary format, for each musical track I must write in the header of the track some bytes containing the size of its following data. As I don’t know that size before the end of the algorithm, I am using the C ftell() function to memorize the position where that size must be written. And when the track is finished, I easily go back to that position using the fseek() function, write the data size, then go back to the current end of the file to write other tracks, and so on. See:

I am really confused on how to do that in Fortran. I have not found exactly equivalent functions. Should I use BACKSPACE as many times as needed (because it goes back only one record at a time)? But then, how to go back to the current end of the file? Making as many READ as needed? (Note that happily, MIDI files are generally quite short: some kilobytes. Performance is not a problem.)

I could probably more easily work with an array, then transfer it to a file. But there is some elegance in the C way.

Thanks for help

Not sure, if it helps:

The inquire statement has a pos specifier that returns the file position for a file connected for stream access in file storage units (in most cases, bytes). For record-based access, there is also the nextrec specifier that returns the number of the next record. You can call inquire whenever you like.

Furthermore, you can call the rewind statement to jump back to the beginning of a file. To check whether or not you have reached the end of a file, call the read statement with iostat specifier, and check the result with is_iostat_end():

integer :: rc
! ...
read (file_unit, iostat=rc) buf

if (is_iostat_end(rc)) then
    ! end of file reached ...
end if
1 Like

You probably want to use the STREAM I/O feature in Fortran. You can specify a starting position as part of the I/O statement. STREAM I/O is designed to be “C-like”.

1 Like

Thanks @billlong and @interkosmos
I was not aware that INQUIRE could be used on an opened file. Using your two answers, I have found that link:
After a quick read, I think it could help me doing the same thing as in C. I will report here my success or failure…

Thanks, it’s a success. In the following program, I write two 0xFF bytes, memorize the position of the second one (before writing it), write two other 0xFF, memorize the final position, replace the second byte by 0x00, then go back to the end and add a final 0x10 byte:

program writing_bytes
    use ISO_FORTRAN_ENV, only: INT8
    implicit none
    integer(INT8)  :: i8
    integer :: status, my_pos, final_pos

    i8 = int(z'FF', kind=INT8)

    open(unit=1, file='bytes.bin', access='stream', status='replace', &
       & action='write', iostat=status)

    write(1, iostat=status) i8
    inquire(1, POS=my_pos)
    print *, "Second byte will be written at the position", my_pos
    write(1, iostat=status) i8
    write(1, iostat=status) i8
    write(1, iostat=status) i8

    inquire(1, POS=final_pos)
    print *, "Temp final position (unwritten) ", final_pos

    print *, "Let's replace the second 0xFF by 0x00"
    write(1, POS=my_pos, iostat=status) 0_INT8

    print *, "Let's add a final 0x10 = 16 byte"
    write(1, POS=final_pos, iostat=status) 16_INT8

    close(1, iostat=status)

    print *
    call execute_command_line("hexdump -C bytes.bin")
end program

The output is:

$ gfortran rewind_to_pos.f90 && ./a.out
 Second byte will be written at the position           2
 Temp final position (unwritten)            5
 Let's replace the second 0xFF by 0x00
 Let's add a final 0x10 = 16 byte

00000000  ff 00 ff ff 10                                    |.....|

P.s. Be careful with the hexdump command: always use the -C option (Canonical) to avoid little-endian problems (by default hexdump is working with 16 bits values…)