I do an fopen once and I am not sure if I have done an fclose down the line, then I want to check if the file is still open and if its open only then do some operation on it. How can I check if the file is already open ?
You can use the ftell() function for this.
ftell(FILE *stream) will return non-negative if the stream
is open. It returns a negative if stream is closed.
I had the same question awhile back, but my respondees concluded that you cannot determine the open-ness of a
file with the run-time library functions alone. You must instead do the record keeping in your own program, to maintain the status of your files.
I was warned off testing for open-ness, basically because your program must follow a pointer dereference to reach the underlying file structure, _iobuf. How can you trust the validity of the FILE pointer? You might get an access violation referencing a null pointer or garbage reference
falling in your address space. If you try to manage the
value of the pointer to avoid the above pitfall, then you are in effect doing the record keeping in your program.
Doing your own housekeeping (setting the pointer to NULL when you close the file) is only portable way you can do this.
FILE *fp=fopen("blah","r"
/* do stuff with file */
fclose(fp);
fp=NULL;
/* ... */
if (fp==NULL) {
/* file is closed */
} else {
/* file is still open */
}
Trying to determine the file's openness by accessing a member of the FILE structure is also highly non-portable because the C standard says absolutely nothing about how the FILE structure should be represented.
There is also nothing in the C standard which requires implementors to have ftell() behave in the way abp has described above. Perhaps he's referring to some compiler docs that implement it this way. The only portable assumption you can make about a negative return from ftell() is that ftell() failed. ftell() will store a value in errno when this happens, but the value it stores is implementation-defined, so you *might* be able to determine that the file wasn't open from this info but, again, your method may or may not work with a different compiler.
Russ
bobbitts@hotmail.com
I think ERRNUM 9 means "Bad file descriptor"
(NT) and "Bad file number" (unix) for most c implementations. Doesnt that give an idea about the status of the file pointer ? Since he has opened the file and was able to read/write from it, the error means that the file descriptor that the file stream fp points to now is no longer valid. Of course this could mean many things apart from a closure of the file stream, but that "could" be one of the reasons ?
Actually this is the error number that my NT/Sun solaris machines printed out when i tried ftell() on a closed file pointer. It may not be portable, but it does give you a not too vague idea of your FILE*.
As you say the *best* method is to set fp to NULL, but
if he doesnt do that ,this could be one among many other
second-rung methods.
The value of errno, if this is what you mean by ERRNUM since there is no ERRNUM in C, isn't relevant to what the OP wants to do. Whatever's stuffed in errno is only of value immediately after an fopen() call.
To the OP:
Another way you could keep track of the status of the status of file pointers is to write a wrapper around fopen() and fclose() and implement a simple stack. Something like this:
/*** untested, incomplete and cheesy ***/
#define DES_CHUNK_SZ 10 /* hold 10 descriptors at first */
struct {
FILE **descriptors; /* all descriptors that are
* currently open */
int des_count; /* # of descriptors currently
in stack */
int des_length; /* current max descriptors */
} file_stack;
/* wrapper for fopen() */
FILE *
my_fopen(const char *file,const char *mode)
{
FILE *fp=fopen(file,mode);
if (fp) {
/* grow or init stack if necessary */
int
my_fclose(FILE *fp)
{
int result=fclose(fp);
if (result==0) {
/* file was closed successfully, remove it
* from the stack */
file_stack[file_stack.des_count--]=NULL;
}
}
/* returns 1 if the file associated with fp is open, 0 if not */
int
file_is_open(FILE *fp)
{
int i;
int found=0;
/* search through the stack for the file pointer */
for (i=0;i<file_stack.des_count;++i) {
if (fp==file_stack) {
found=1;
}
}
return found;
}
Personally, I would just stick with setting the file pointer to NULL after opening it You could even use a wrapper for fclose() to do this for you:
int
my_fclose(FILE **fp)
{
int result=fclose(*fp);
*fp=NULL;
return result;
}
I was asking to check the errno after the ftell() call. Something like below.
#include <errno.h>
{
....
FILE *fp;
int ret_value;
/* do your stuff on fp */
extern int errno;
ret_value = ftell(fp);
if ( ret_value < 0 )
{
printf("%s\n", strerror(errno));
}
else
{
printf("%s\n", "Everything is fine"
}
}
I had meant the errno that is set after call to ftell(). If it is 0 then ftell() succeeds
and if it is one of the values as below , ftell() failed with the reason against the number.
Actually Visual C++ 5.0 gives pretty specific error numbers for such
a failed function on a file descriptor. Here are some of them.
EBADF - Bad file number. There are two possible causes:
1) The specified file handle is not a valid file-handle value or does not refer to an open file.
2) An attempt was made to write to a file or device opened for read-only access
EEXIST - Files exist. An attempt has been made to create a file that already exists.
For example, the _O_CREAT and _O_EXCL flags are specified in an _open call, but
the named file already exists.
EMFILE - Too many open files. No more file handles are available, so no more files can be opened.
If you are checking these error numbers after a call to fopen(), then they give a wide range
of things that could have gone wrong. But if you get say EBADF after calling ftell() on a file
that you were writing to sometime back, then obviously the reason is the (1) under EBADF.
What I am trying to tell is that though this is not a very good way of doing it, it does
give you an idea of what went wrong.
I think the idea of writing your own fclose() makes sense.
You could write your own ftell() also making use of the fact that fp is NULL..
I guess it's a cost-benefit analysis that you have to perform to decide what's the best solution for you. If a given piece of code is only going to run on one platform under one compiler, then I think your solution is reasonable. Although, notice that EBADF in your example gives 2 possibilities, so you're still not totally in the clear
For me, I like to assume the least I can about these things so I can re-use code easily across platforms and implementations. I can see going the route of relying on the return value of functions that differ across implementations and before long my code looks like this:
int ret=ftell(fp);
#if defined __DJGPP__
#elif defined __GCC__
#elif defined __SOME_OTHER_COMPILER__
/* ... */
All for this simple thing
Such an approach would also warrant a very careful inspection of each compiler's documentation because with each compiler there is the possibility that passing ftell() an invalid FILE pointer might result in a program crash or other such undesirable behavior. The C standard doesn't prevent an implementor from implementing ftell() in this way. In other words, ftell() could very well blithely assume that the FILE pointer you pass to it refers to an opened stream.
Of course, if a compiler documents that ftell() can deal with such FILE pointers gracefully, as MSVC++ appears to, you don't have to worry about it /for that implementation/. But beware when porting time comes around
Russ
bobbitts@hotmail.com
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.