Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Diehl__Martin
Novice
973 Views

Reading file of length zero

Jump to solution

I have a general reading routine that crashes for empty files (ASCII).

The following minimal example shows this behavior (compile; touch empty.txt; ./out) when compiled with ifort version 19.0.2.187. Is that the expected behavior, i.e. would I need to check for fileLength/=0 or is ifort suppost to figure this out.

program test

 character(len=:), allocatable :: a
 a = IO_read('empty.txt')

 print*, len(a)
 print*, '#'//a//'#'

contains

function IO_read(fileName) result(fileContent)

  character(len=*),  intent(in) :: fileName
  character(len=:), allocatable :: fileContent
  integer ::  &
    fileLength, &
    fileUnit, &
    myStat

  inquire(file = fileName, size=fileLength)
  open(newunit=fileUnit, file=fileName, access='stream',&
       status='old', position='rewind', action='read',iostat=myStat)
  if(myStat /= 0) stop 1
  allocate(character(len=fileLength)::fileContent)
  read(fileUnit) fileContent
  close(fileUnit)

end function IO_read

end program test

 

0 Kudos
1 Solution
Steve_Lionel
Black Belt Retired Employee
806 Views

Here's my analysis of the situation...

The READ is attempting to read zero bytes from an empty file connected for unformatted stream access. The standard says that an end-of-file condition occurs when "an attempt is made to read beyond the end of a stream file." Since the READ is not trying to read beyond the end of the file, the file position should remain unchanged and the READ should succeed.

Therefore, I believe this is an error on the part of ifort and should be reported to Intel using the Online Service Center.

View solution in original post

31 Replies
Steve_Lionel
Black Belt Retired Employee
320 Views

That's interesting, and another bug. Let me do some tests on that.

John_Campbell
New Contributor II
320 Views

Why not simply respond to " inquire(file = fileName, size=fileLength)" for empty (size=0) or non-existent (size=-1), without opening the file.

Perhaps use  if ( fileLength <= 0) then ; allocate(character(len=0)::fileContent) ; else ; ...

Isn't fileLength = -1 already a problem ?

Diehl__Martin
Novice
320 Views

John Campbell wrote:

Why not simply respond to " inquire(file = fileName, size=fileLength)" for empty (size=0) or non-existent (size=-1), without opening the file.

Perhaps use  if ( fileLength <= 0) then ; allocate(character(len=0)::fileContent) ; else ; ...

The first solution leaves fileContent unallocated which requires further checks in other parts of the code (the MWE given here is not the full code).

A non-existing file is certainly a problem, but I sometimes have optional files and simply check whether they exist (with inquire)

In general, I prefer to write code without special cases.

Unfortunately, the use of modern Fortran reveals often compiler glitches (not just in Intel products) that require to use a non-optimal solution. Hence, when in doubt I try to clarify whether my code is invalid or whether the compiler does not respect the standard.

Steve_Lionel
Black Belt Retired Employee
320 Views

I can't reproduce the iostat comparison issue you mentioned in post 21. The iostat properly comes back as -1 and comparing /= 0 works.

Diehl__Martin
Novice
320 Views

Dear Steve,

many thanks for your investigations. Actually, I think my explanation was a little bit misleading.

  • If I read a file of length N, N>0, into a string of length N, the iostat return value is 0. Hence, I assume an error for iostat /= 0 (error: iostat > 0, read beyond EOF: iostat = -1).
  • If I read a file of length 0 into a sting of length 0, the iostat return value is -1. This seems to be a contradiction to your statement from the standard which states that -1 is returned if "an attempt is made to read beyond the end of a stream file." According to my understanding, reading 0 bytes from a 0 bytes file should also result in iostat = 0 because EOL was not reached (file length matches length of read). Due to this unexpected behavior, I need to change my code to accept an iostat of -1, even though this signals that I tried to read more information than present in the file

Finally, just for the sake of completeness (I understand that you have confirmed that already): If the iostat argument for the read statement is missing I get an segmentation fault if reading a 0 length file. This behavior is cured if iostat is present as an actual argument

andrew_4619
Honored Contributor I
320 Views

It would be better to use the variable with the IOSTAT_END parameter of the intrinsic module ISO_FORTRAN_ENV, or the IS_IOSTAT_END function. 

Diehl__Martin
Novice
320 Views

andrew_4619 wrote:

It would be better to use the variable with the IOSTAT_END parameter of the intrinsic module ISO_FORTRAN_ENV, or the IS_IOSTAT_END function. 

many thanks, I did not know about this. Much easier to read

Steve_Lionel
Black Belt Retired Employee
320 Views

Diehl, Martin wrote:

  • If I read a file of length 0 into a sting of length 0, the iostat return value is -1. This seems to be a contradiction to your statement from the standard which states that -1 is returned if "an attempt is made to read beyond the end of a stream file." According to my understanding, reading 0 bytes from a 0 bytes file should also result in iostat = 0 because EOL was not reached (file length matches length of read). Due to this unexpected behavior, I need to change my code to accept an iostat of -1, even though this signals that I tried to read more information than present in the file

Right - that's a bug. You should be getting iostat=0 for reading zero bytes as you are not attempting to read past the end of file.

jimdempseyatthecove
Black Belt
320 Views

>>You should be getting iostat=0 for reading zero bytes as you are not attempting to read past the end of file.

What is supposed to happen when you issue this 0-byte read, as the next read following a >0 byte read that returned EOF (-1)?
IOW the internal state is "read beyond end of file". This may present a different behavior should the file be opened for shared use or for exclusive use.

Martin, had your test program (legitimately) encountered an EOF return... then issued the 0-byte read?

Jim Dempsey

Steve_Lionel
Black Belt Retired Employee
320 Views

If the READ does not attempt to transfer data, it should not get an EOF condition, no matter where it is in a file connected for stream access. It is different for non-stream access.

Diehl__Martin
Novice
320 Views

jimdempseyatthecove (Blackbelt) wrote:

Martin, had your test program (legitimately) encountered an EOF return... then issued the 0-byte read?

No, the file is just opened (as in the example given in my initial post)

Reply