Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28435 Discussions

problem reading/writing binary direct access files

Samantha_G_
Beginner
895 Views

I've been given a program with this basic information:

integer*4 wind(10585,4,17)

    open(unit=8,file='swind.dat',form='unformatted',
     +        access='direct',recl=4*719780)

    write(8,rec=1) wind

It's taking a 3d array and writing it as a single record into the output file.  However the file it generates is 11 mb in size.  This program was run on UNIX (compiled by gcc) to generate the file and it was a little under 3mb in size.

I did check of the binary contents and noticed this.  The files are the same and then this file on the PC is padding a bunch of zeros afterward.  It's causing my program that reads this file to return zeros instead of numbers.

My reading program's open/write statements look like this where nbytes is 4*10585 or 42,340 and the irec variable is going from 29 to 44.

        open (unit=units(nextop),file=filename,status='old',
     &recl=nbytes,access='direct',iostat=istat,form='unformatted')

      read (iunit,rec=irec,iostat=istat) (wdata(i),i=1,mxrec)

I'm thinking since the PC version of this file is so much larger than the UNIX version, I'm guessing the writing Fortran program is doing something funny.  At the same time, I'm also surprised I'm not getting numbers back from the reading program because the first half of the PC and UNIX files are identical.

Is this a problem with the code or am I missing a compiler flag?  I just compiled this program without any additional flags when I created a console program.

0 Kudos
6 Replies
IanH
Honored Contributor II
895 Views

The units of recl vary between compilers.  By default with ifort it is in four byte words (4 x ~ 3MB = ~12 MB !).  gfortran uses byte units.

You can change ifort to use bytes units by using the /assume:byterecl compiler option.  Recent Fortran standards recommand that the units of RECL be bytes (hence /standard-semantics includes /assume:byterecl), but I could imagine lots of users getting rather cranky if the long standing default for ifort and its ancestors was changed. 

You can use an INQUIRE statement with an IOLENGTH specifier to determine the required record length for a particular list of io-items that removes the need to know the units of RECL in advance.  This is robust practice.

With the mismatch in RECL between the write and the read, you are implicitly relying on the compiler using a particular on-disk structure for its direct access, unformatted files (a structure that doesn't store record lengths in any way).  This assumed structure is pretty common, but it is not required by the Fortran standard (ifort will use a different structure that breaks your assumption with certain compiler command line options).  I suggest that a clearer and more robust arrangement would be to write the array out in the same manner that you read it (same RECL, same number of records).  Alternatively, use unformatted, stream access, and for reading do the equivalent to record positioning yourself using the POS specifier.  The size of a file storage unit under stream access could technically not be a byte, but all the compiler authors that ever wanted to choose something different have now been safely locked up in secure institutions.

0 Kudos
Samantha_G_
Beginner
895 Views

Ian,

I tried to recompile the writing code with /assume:byterecl.  However when I reran the new executable, the output file was still the same size.  It did not get any smaller.  That should have worked without me having to change the code, shouldn't it?

Sorry forgot to mention that on the receiving or reading end:

integer wtdata(1439560)
parameter (mxrec = 10585)

So the fact that I wrote it initially as a 3d array and am now reading it as a 1d array is the reason it's unhappy?

0 Kudos
IanH
Honored Contributor II
895 Views

Delete the output file before you rerun the program compiled with the /assume:byterecl option, or consider adding the STATUS='REPLACE' specifier on the OPEN statement.

0 Kudos
Samantha_G_
Beginner
895 Views

Hmm...

Good news:  The file shrunk down to 2.8 mb on the writing end

Bad news:  The reading end is now giving an iostat(36) error when it's trying to read the file.

0 Kudos
IanH
Honored Contributor II
895 Views

Did you recompile the reader with /assume:byterecl?

0 Kudos
Samantha_G_
Beginner
895 Views

Narf! @$%@#@#$@#!!!!

Thank you Ian.  Everybody is happy now.

0 Kudos
Reply