2

I have a Fortran file that generates some numbers in a two-dimensional array, for example:

program WriteBinaryFile

    real(kind=4)::myarray(140,130)
    integer(kind=4):: num1, num2
    character*120 filename
    
    ! Insert some numbers, i.e., number 1 through 18200=140*130
    do num=1,140
        do num2=1,130
           myarray(num1,num2)=(num1-1)*130+num2
        end do
    end do

    filename="binaryFile"
        
    open(22,file=filename,form='unformatted',access='direct',recl=140*130*4,&
         iostat=ios)

    irec=1
    write(22,rec=irec)myarray

    close(22)

    ! Some other things happen.

    end program WriteBinaryFile

I am trying to read this into Python, but so far I have had no success at all; with either numpy.fromfile or scypi.io.FortranFile:

import numpy as np
f = np.fromfile("binaryFile")

or

from scypi.io import FortranFile
f = FortranFile("binaryFile", "r")
myarray = f.read_reals()

They don't work. The first program outputs a bunch of numbers that don't make sense and the latter throws an exception that states: "scipy.io._fortran.FortranFormattingError: End of file in the middle of a record".

I have tried to do different things, as outlined in the posts:

  1. Reading Fortran binary file in Python
  2. https://numpy.org/doc/stable/reference/generated/numpy.fromfile.html
  3. https://docs.scipy.org/doc/scipy/reference/generated/scipy.io.FortranFile.html
  4. etc.

to no avail! With the first link being the closest. Help solving this issue would be appreciated.

I have been able to recover the file content using Fortran, but not Python.

Other information.

  • This is a transcript of the program from my machine. The original file was generated in a machine of which I have no knowledge about, other than it generates the file; i.e., no idea of encoding, compiler version, etc..
Andrumen1
  • 49
  • 1
  • 8
  • Your `recl` computation is unsafe and will only work for specific compilers. You should use `inquire(iolength=)` https://stackoverflow.com/questions/32686720/reading-writing-fortran-direct-access-unformatted-files-with-different-compilers Also, `kind=4` is not portable either and will fail to compile with some compilers or could mean something else with other compilers https://stackoverflow.com/questions/838310/fortran-90-kind-parameter https://stackoverflow.com/questions/3170239/fortran-integer4-vs-integer4-vs-integerkind-4 – Vladimir F Героям слава Jun 10 '22 at 18:13
  • Thanks for your comment. Will try to work through your example, but the posted program is the program I was given, that is, some person wrote the program to collect some data and write it and I am in charge of making Python read it; so I can't change the way it's written. Thanks! – Andrumen1 Jun 11 '22 at 13:13

2 Answers2

3

Firstly, your Fortran example is incorrect. It creates some myarray, but then writes some toast. Always use IMPLICIT NONE in any Fortran code you share with others.

scipy.io.FortranFile will be useless for this case. It is for sequential access files. Your file is direct access. In practice, the direct access file will be the same as a stream access file and the same as a file written in C (but in column-major order).

You can use numpy.fromfile to read the data

 array_data = np.fromfile(file, dtype=np.float32).reshape([nx, ny], order='F')

If the machine used to create the file was some bigendian-RISC, you may have to convert the byte order (ndarray.byteswap or by reading the buffer as bigendian directly).

I suggest opening the file in a hex editor and see whether the numbers stored there make sense as littleendian floats or as bigendian floats.

  • Sorry, corrected "toast" for "myarray", just a copy/paste -> modification typo. Also, this is the file provided by the creator of the file, not myself, I am just tasked with reading the file in Python. Thanks for the suggestions though. Will try it out and will upvote if successful. Thanks! – Andrumen1 Jun 11 '22 at 21:01
  • Thanks! Your answer is closer to that of the solution I found. It was just that there was no "implicit none". The person who got the file didn't he was using the "implicit none" statement, so it was difficult. – Andrumen1 Jun 15 '22 at 17:52
0

The docs (https://docs.scipy.org/doc/scipy/reference/generated/scipy.io.FortranFile.html) say that you should use file extensions, as seen here:

from scipy.io import FortranFile
f = FortranFile('test.unf', 'w')
f.write_record(np.array([1,2,3,4,5], dtype=np.int32))
f.write_record(np.linspace(0,1,20).reshape((5,4)).T)
f.close()

Try writing it with the file extension. Hope this helps!

  • 1
    Errr, OP wants to **read** file written by Fortran into Python... not write. – Mark Setchell Jun 10 '22 at 17:33
  • I wasn't saying use this code. I was saying this is the example, showing that you need to use the end of the file. – Gerald Negvesky Jun 10 '22 at 20:03
  • Thanks to both of you. Unfortunately I can't change the way it's written, since the code comes from an external source. I will suggest it though. – Andrumen1 Jun 11 '22 at 13:15
  • 1
    `FortranFile` is for sequential access Fortan files. Those are very different to the direct access file Andrumen1 is working with. The sequential file contains additional record markers. The actual binary content is not standardized and may (will) differ between compilers. – Vladimir F Героям слава Jun 12 '22 at 06:36
  • 1
    Notice the note in your link *"Consider using Fortran direct-access files or files from the newer Stream I/O, which can be easily read by numpy.fromfile."*. – Vladimir F Героям слава Jun 12 '22 at 06:38
  • But most importantly, I do not really understand what you answer is saying. Are you saying that the ".unf" extension is saying? That is nonsense. Or that one should extend the file with some data? The example you copied from the docs does not show such a thing, the record matrkers are added by `FortranFile` automatically, the examply just shows how to store to different records with arrays of different types. – Vladimir F Героям слава Jun 12 '22 at 06:43
  • @VladimirFГероямслава, I could not be more clear. You are supposed to include the file extension. You can't just say `FortranFile("file", "r")` , you have to say `FortranFile("file.extension", "r")`. Python won't know what file you are talking about otherwise. If his file is called `binaryFile.txt`, he should change his code to `f = FortranFile("binaryFile.txt", "r"`) Whatever the ending is what he should write – Gerald Negvesky Jun 12 '22 at 09:17