I am trying to read a binary file in Fortran. The file contains strings and numbers. I know how the binary file was created, since I have the code. Here is the minimal reproducible example of code that creates such a binary file:
PROGRAM MAIN
USE, INTRINSIC :: ISO_FORTRAN_ENV
IMPLICIT NONE
INTEGER, PARAMETER :: I32 = INT32
INTEGER, PARAMETER :: R32 = REAL32
CHARACTER(1_I32) , PARAMETER :: END_REC = CHAR(10_I32) !end-character for binary-record finalize
CHARACTER(*), PARAMETER :: MAIN_FILE_NAME = "main_file"
INTEGER(KIND=I32) :: E_IO, I, UNIT_MAIN, UNIT_SCRATCH
INTEGER(KIND=I32) :: N_BYTE !number of byte to be written/read
INTEGER(KIND=I32) :: IOFFSET, IOFFSET_1, IOFFSET_2
INTEGER(KIND=I32) , PARAMETER :: MAXLEN = 500_I32
CHARACTER(LEN=MAXLEN) :: S_BUFFER
REAL(KIND=R32) :: RPRO
INTEGER(KIND=I32) :: IPRO
INTEGER(KIND=I32), PARAMETER :: N_INT_VAL = 2, N_REAL_VAL = 3
REAL(KIND=R32), DIMENSION(N_REAL_VAL) :: X, Y, Z
INTEGER(KIND=I32), DIMENSION(N_INT_VAL) :: INT_ARRAY
CHARACTER(2) :: VAR_TYPE
INTEGER(KIND=I32) :: N_V
REAL(KIND=R32), ALLOCATABLE :: V_R4(:)
REAL(KIND=I32), ALLOCATABLE :: V_I4(:)
!initlialization of data arrays
X = (/0.0_R32, 1.0_R32, 3.0_R32/)
Y = (/0.0_R32, 2.0_R32, 1.0_R32/)
Z = (/0.0_R32, 4.0_R32, 3.0_R32/)
INT_ARRAY = (/1_I32, 100_I32/)
UNIT_MAIN = 11
UNIT_SCRATCH = 12
!open the binary file
OPEN(UNIT=UNIT_MAIN, FILE=MAIN_FILE_NAME, &
FORM='UNFORMATTED', ACCESS='STREAM', &
ACTION='WRITE', CONVERT='BIG_ENDIAN', IOSTAT=E_IO)
!open SCRATCH file for appending raw binary data
OPEN(UNIT=UNIT_SCRATCH, &
FORM='UNFORMATTED', ACCESS='STREAM', &
ACTION='READWRITE', CONVERT='BIG_ENDIAN', STATUS='SCRATCH', IOSTAT=E_IO)
IOFFSET = 0_I32 ! initializing offset
WRITE(UNIT=UNIT_MAIN, IOSTAT=E_IO)'<version="1.0"? byte_order="BigEndian>'//END_REC
!------prepare real points X, Y, Z------
WRITE(S_BUFFER, FMT='(A,'//'(I12)'//',A)', IOSTAT=E_IO)'<NumberOfRealPoints="',N_REAL_VAL,'">'
WRITE(UNIT=UNIT_MAIN, IOSTAT=E_IO)TRIM(S_BUFFER)//END_REC
WRITE(S_BUFFER,FMT='(I8)', IOSTAT=E_IO)IOFFSET
WRITE(UNIT=UNIT_MAIN, IOSTAT=E_IO)'<DataArray type="Float32" NumberOfComponents="3" offset="',TRIM(S_BUFFER),'">'//END_REC
N_BYTE = 3_I32*N_REAL_VAL*SIZEOF(RPRO)
IOFFSET = IOFFSET + sizeof(IPRO) + N_BYTE !0 + size(N_BYTE) + size(X+Y+Z) = 40 bytes
IOFFSET_1 = IOFFSET
WRITE(UNIT=UNIT_SCRATCH, IOSTAT=E_IO) N_BYTE,'R4',3_I32*N_REAL_VAL
WRITE(UNIT=UNIT_SCRATCH, IOSTAT=E_IO)(X(I),Y(I),Z(I), I=1_I32, N_REAL_VAL) !write real points to SCRATCH file
!--------------------------------------------------
!------prepare integer array INT_ARRAY------
WRITE(S_BUFFER, FMT='(A,'//'(I12)'//',A)', IOSTAT=E_IO)'<NumberOfIntValues="',N_INT_VAL,'">'
WRITE(UNIT=UNIT_MAIN, IOSTAT=E_IO)TRIM(S_BUFFER)//END_REC
WRITE(S_BUFFER,FMT='(I8)', IOSTAT=E_IO)IOFFSET
WRITE(UNIT=UNIT_MAIN, IOSTAT=E_IO)'<DataArray type="Int32" NumberOfComponents="1" offset="',TRIM(S_BUFFER),'">'//END_REC
N_BYTE = 1_I32*N_INT_VAL*SIZEOF(IPRO)
IOFFSET = IOFFSET + sizeof(IPRO) + N_BYTE !size(N_BYTE) + size(X+Y+Z) + size(N_BYTE) + size(INT_ARRAY) = 40 bytes + 12 bytes = 52 bytes
IOFFSET_2 = IOFFSET
WRITE(UNIT=UNIT_SCRATCH, IOSTAT=E_IO) N_BYTE,'I4',1_I32*N_INT_VAL
WRITE(UNIT=UNIT_SCRATCH, IOSTAT=E_IO)(INT_ARRAY(I), I=1_I32, N_INT_VAL)
!--------------------------------------------------
WRITE(UNIT=UNIT_MAIN, IOSTAT=E_IO)'<end text>'//END_REC
WRITE(UNIT=UNIT_MAIN, IOSTAT=E_IO)'_'
ENDFILE(UNIT=UNIT_SCRATCH, IOSTAT=E_IO)
REWIND(UNIT=UNIT_SCRATCH, IOSTAT=E_IO)
DO
READ(UNIT=UNIT_SCRATCH, IOSTAT=E_IO, END=100) N_BYTE, VAR_TYPE, N_V
SELECT CASE(VAR_TYPE)
CASE('R4')
ALLOCATE(V_R4(1_I32:N_V))
READ (UNIT=UNIT_SCRATCH, IOSTAT=E_IO)(V_R4(I),I=1_I32,N_V)
WRITE(UNIT=UNIT_MAIN, IOSTAT=E_IO) N_BYTE, (V_R4(I),I=1_I32,N_V)
DEALLOCATE(V_R4)
CASE('I4')
ALLOCATE(V_I4(1_I32:N_V))
READ (UNIT=UNIT_SCRATCH, IOSTAT=E_IO)(V_I4(I),I=1_I32,N_V)
WRITE(UNIT=UNIT_MAIN, IOSTAT=E_IO) N_BYTE, (V_I4(I),I=1_I32,N_V)
DEALLOCATE(V_I4)
END SELECT
END DO
100 CONTINUE
WRITE(UNIT=UNIT_MAIN, IOSTAT=E_IO)END_REC
WRITE(UNIT=UNIT_MAIN, IOSTAT=E_IO)'<end file>'//END_REC
CLOSE(UNIT=UNIT_SCRATCH, IOSTAT=E_IO)
CLOSE(UNIT=UNIT_MAIN, IOSTAT=E_IO)
CALL READ_FILE(MAIN_FILE_NAME,N_INT_VAL,N_REAL_VAL,IOFFSET_1,IOFFSET_2)
END PROGRAM MAIN
The code writes into file text header (7 strings) and then the arrays X, Y, Z, INT_ARRAY and the footer at the end. I am able to read the text (7 string) using READ_FILE subroutine:
SUBROUTINE READ_FILE(MAIN_FILE_NAME,N_INT_VAL,N_REAL_VAL,IOFFSET_1,IOFFSET_2)
USE, INTRINSIC :: ISO_FORTRAN_ENV
IMPLICIT NONE
INTEGER, PARAMETER :: I32 = INT32
INTEGER, PARAMETER :: R32 = REAL32
INTEGER(KIND=I32) :: E_IO, I, N_V
CHARACTER(*), INTENT(IN) :: MAIN_FILE_NAME
INTEGER(KIND=I32), INTENT(IN) :: N_INT_VAL, N_REAL_VAL
INTEGER(KIND=I32), INTENT(IN) :: IOFFSET_1, IOFFSET_2
CHARACTER(LEN=100) :: DUMMY
CHARACTER(LEN=1) :: ONECH
INTEGER(KIND=I32) :: N_BYTE
REAL(KIND=R32), DIMENSION(:), ALLOCATABLE :: REAL_ARRAY_READ
INTEGER(KIND=I32), DIMENSION(:), ALLOCATABLE :: INT_ARRAY_READ
ALLOCATE(REAL_ARRAY_READ(3_I32*N_REAL_VAL), INT_ARRAY_READ(N_INT_VAL))
OPEN(UNIT=11,FILE=TRIM(MAIN_FILE_NAME),STATUS='old',iostat=E_IO)
READ(UNIT=11,FMT='(A)') DUMMY !'<version="1.0"? byte_order="BigEndian>'
READ(UNIT=11,FMT='(A)') DUMMY !'<NumberOfRealPoints="3">'
READ(UNIT=11,FMT='(A)') DUMMY !'<DataArray type="Float32" NumberOfComponents="3" offset="0">'
READ(UNIT=11,FMT='(A)') DUMMY !'<NumberOfIntValues="2">'
READ(UNIT=11,FMT='(A)') DUMMY !'<DataArray type="Int32" NumberOfComponents="1" offset="40">'
READ(UNIT=11,FMT='(A)') DUMMY !'<end text>'
READ(UNIT=11,FMT='(A)') ONECH !'_'
N_V = 3_I32*N_REAL_VAL
!READ(UNIT=11) N_BYTE, (REAL_ARRAY_READ(I),I=1_I32,N_V)
CLOSE(11)
END SUBROUTINE READ_FILE
However, I am not sure how to extract the numerical values of arrays from this binary file. Do I need to reopen the file as UNFORMATTED and somehow position reading after the text? Could you please help with correctly reading the values of X, Y, Z, INT_ARRAY (REAL_ARRAY_READ, INT_ARRAY_READ respectively)?