In a program I am improving, I noticed that Fortran does not detect file existing or not. This led to a logic error which has not been fixed. I highly appreciate if you could point out the problems or errors and give me your corrections.
open(unit=nhist,file=history,iostat=ierr)!This setting cannot exit program if file does not exist because ierr is always 0
if (ierr /=0) then
write(*,*)'!!! error#',ierr,'- Dump file not found'
stop
endif
!I used below statement, the program exits even though a file is existing
open(unit=nhist,file=history,err=700)
700 ierr=-1
if (ierr /=0) then
write(*,*)'!!! error#',ierr,'- Dump file not found'
stop
endif
There are two distinct problems here. Let's look at them separately.
First, consider
open(unit=nhist,file=history,iostat=ierr)
The comment suggests that ierr is always set to zero. Well, why shouldn't it be set to zero? ierr should be non-zero in the case the case of an error, but is the file not existing an error?
Not necessarily. In the absence of a status= specifier the default status='unknown' is taken. The compiler doesn't have to (and is unlikely to) treat opening in this case as an error if the file doesn't exist. It's likely to create it as needed on a write, or complain when trying to read.
Adding status='old' to the open statement is the usual way of saying "the file should exist".
Second, consider
open(unit=nhist,file=history,err=700)
700 ierr=-1
if (ierr /=0) then
...
If there's an error here, execution is transferred to the statement labelled 700. From this statement ierr is set to a non-zero value and off we go to the if construct to handle that error.
It's just that the statement labelled 700 also happens to be executed even without an error: it's simply the next statement after the open and there's no branch to miss it. [I could give an example of such branching, but I don't want to encourage use of err= in modern code. With the working iostat= things are far preferable.]
But if you just wish to test the existence of a file, consider inquire-by-file:
logical itexists
inquire (file=history, exist=itexists)
if (.not.itexists) error stop "No file :("
Some would argue this is even better than having status='old' in an open statement.
Related
I have a Fortran program that needs to read ASCII files, however the list of files sometimes includes a file of size 0. The program then crashes when trying to read this file. I have not find any way so far that will allow me to flag such a file.
I have following READ statement in my code
read(10,220,END=320,ERR=195)parm(1:)
although I expect code to go to statement 195, or to statement 320, without crashing, it crashes
this is where the code crashes when the file size is zero, with the following messages
...
fmt: end of file
apparent state: unit 10 named junko.con
last format: (A)
lately reading sequential formatted external IO
I tried using the INQUIRE statement
inquire (unit=10,SIZE=nsize), but the program would not compile
the OPEN statement did not give any error when opening the zero size file, and the values of IOSTAT was the same, irrespective of the file size
As Ian noted, any modern Fortran compiler should have INQUIRE. A simple test of
program foo
integer sz
inquire(file='tmp.dat',size=sz)
print *, sz
end program foo
with an empty tmp.dat file sets sz=0.
I need to create a file in fortran and then read the data in the file.
call execute_command_line('pwd > workdir.dat')
open(unit=10, file='workdir.dat', status='replace', IOSTAT=open_stat)
if (open_stat /= 0) stop "Reading workdir.dat file Error"
read(10,"(A)") workdir
close(10)
However, workdir.dat is empty when I try to open it, giving me serious open error. It seems that the system only flush the content of workdir.dat to the file at the end of the program. How do I make sure workdir.dat is ready to use before open ?
The open statement includes the clause status=replace which, in effect, tells the run time system that to discard the file's contents and write them anew. To be precise, the language standard states wrt to the status specifier on an open statement:
If REPLACE is specified and the file does exist, the file is deleted,
a new file is created with the same name, and the status is changed to
OLD.
Change the clause to status=old which is the correct specification for this case.
In a program I am improving, I noticed that Fortran does not detect file existing or not. This led to a logic error which has not been fixed. I highly appreciate if you could point out the problems or errors and give me your corrections.
open(unit=nhist,file=history,iostat=ierr)!This setting cannot exit program if file does not exist because ierr is always 0
if (ierr /=0) then
write(*,*)'!!! error#',ierr,'- Dump file not found'
stop
endif
!I used below statement, the program exits even though a file is existing
open(unit=nhist,file=history,err=700)
700 ierr=-1
if (ierr /=0) then
write(*,*)'!!! error#',ierr,'- Dump file not found'
stop
endif
There are two distinct problems here. Let's look at them separately.
First, consider
open(unit=nhist,file=history,iostat=ierr)
The comment suggests that ierr is always set to zero. Well, why shouldn't it be set to zero? ierr should be non-zero in the case the case of an error, but is the file not existing an error?
Not necessarily. In the absence of a status= specifier the default status='unknown' is taken. The compiler doesn't have to (and is unlikely to) treat opening in this case as an error if the file doesn't exist. It's likely to create it as needed on a write, or complain when trying to read.
Adding status='old' to the open statement is the usual way of saying "the file should exist".
Second, consider
open(unit=nhist,file=history,err=700)
700 ierr=-1
if (ierr /=0) then
...
If there's an error here, execution is transferred to the statement labelled 700. From this statement ierr is set to a non-zero value and off we go to the if construct to handle that error.
It's just that the statement labelled 700 also happens to be executed even without an error: it's simply the next statement after the open and there's no branch to miss it. [I could give an example of such branching, but I don't want to encourage use of err= in modern code. With the working iostat= things are far preferable.]
But if you just wish to test the existence of a file, consider inquire-by-file:
logical itexists
inquire (file=history, exist=itexists)
if (.not.itexists) error stop "No file :("
Some would argue this is even better than having status='old' in an open statement.
I have a little Problem reading a file in Fortran. As you can see I am lopping over a file reading certain records with a specific length.
What happens is, when it comes to a certain record I'm getting an IOSTAT Error 5002. Now my question is what does this error mean: is it end of file or there is no record left or something else? Can I ignore it?
I am using MinGW GFortran 4.8.0.
Here's the code:
PROGRAM test_read
INTEGER*4 HCM_error
DOUBLE PRECISION N_Record(22)
CHARACTER*8 C_Record(22)
EQUIVALENCE (N_Record,C_Record)
OPEN (UNIT=11, FILE='C:/BORDER/D__HOL.000',STATUS='OLD', ACCESS='DIRECT',RECL=176, ACTION='READ', IOSTAT=IOS)
HCM_error=0
DO N_rec = 1, 2000
READ (11, REC=N_rec, IOSTAT=IOS) C_Record
WRITE(*,*) "|",IOS,' ',N_rec,' ',N_record(21),' ',N_record(22),"|"
!End of file reached (or non existing record) ?
IF ((IOS .LT. 0) .OR. (IOS .EQ. 36)) EXIT
IF (IOS .NE. 0) THEN
!Error in (border-) line data
HCM_Error = 1049
EXIT
END IF
END DO
CLOSE(UNIT=11)
WRITE (*,*) HCM_error
END PROGRAM
The non-zero values returned by an iostat= specifier are not portable across compilers. If you wish to determine what a particular code means then you have two options:
read the compiler's documentation (if it exists)
use the iomsg= specifier with a character variable
In this case, when you tried iomsg= you got the message "Non-existing record number". So, problem solved.
Well, almost. There's more to say.
You may be surprised that you are going through records in turn in direct access, but are reaching a "no record" state without first reaching an "end of file" state. You are testing (IOS .LT. 0) with a comment "!End of file reached".
When reading a file connected for direct access, the end of file condition doesn't arise.
What can you do to detect that the record isn't a valid number, beyond the end of the file? Not much, portably, but any positive number from iostat= indicates an error condition. You know now, though, what this particular 5002 means.
I should probably also add that the character variable for iomsg= is defined by the transfer statement only if there isn't success. Consider it only if you know the transfer failed.
I compile a fortran 77 code using gfortran and get the following error:
10 open (23,file=outfile,status='old',access='append',err=10)
1
Warning: Branch at (1) may result in an infinite loop
This happens several times.
One of the output files looks like the following:
^L6a10È <90> ) &<9b>LÓLÓLÕ<91><90> <90> <90> È <8e><9b>LÓLÓLÕ<93>2
!MERCURY ¢¤õ/!ô<8a><8a><90> ÿ<90> ÿ<90> ÿÌÖÏ©ü}M<91>
"VENUS «}>±{©±<8b><90> ÿ<90> ÿ<90> ÿʺ93¿<8d>d<91>
However, it should just look like a table of text.
Any ideas?
Your line of code
10 open (23,file=outfile,status='old',access='append',err=10)
specifies that the open statement should transfer control to itself (label 10) in case an error is encountered, so any error could trigger an infinite loop. It also suppresses the output of error messages. If you want to just check for an error status, I would suggest using the iostat and/or iomsg (Fortran 2003) arguments:
open (23, file=outfile, status='old', access='append', iostat=ios, iomsg=str)
Here ios is an integer that will be zero if no errors occur and nonzero otherwise, and str is a character variable that will record the corresponding error message.
The err= argument in your open statement specifies a statement label to branch to should the open fail for some reason. Your code specifies a branch to the line labelled 10 which happens to be the line containing the open statement. This is probably not a good idea; a better idea would be to branch to a line which deals gracefully with an error from the open statement.
The warning from gfortran is spot on.
As to the apparent garbage in your output file, without sight of the code you use to write the garbage (or what you think are pearls perhaps) it's very difficult to diagnose and fix that problem.