tags:

views:

8579

answers:

6

Is there a better way than simply trying to open the file?

int exists(const char *fname)
{
    FILE *file;
    if (file = fopen(fname, "r"))
    {
        fclose(file);
        return 1;
    }
    return 0;
}
+11  A: 

Yes. Use stat(). See link.

Stat will fail if the file doesn't exist, otherwise most likely succeed. If it does exist, but you have no read access to the directory where it exists, it will also fail, but in that case any method will fail (how can you inspect the content of a directory you may not see according to access rights? Simply, you can't).

Oh, as someone else mentioned, you can also use access(). However I prefer stat(), as if the file exists it will immediately get me lots of useful information (when was it last updated, how big is it, owner and/or group that owns the file, access permissions, and so on).

Mecki
access is preffered if you only need to know if the file exists. Stat() can have a large overheard if you don't need all the extra info.
Martin Beckett
Actually when I list a directory using ls-command, it calls stat for every file being present there and that running ls has a large overhead is pretty new to me. Actually you can run ls on directories with thousands of files and it returns in a fraction of a second.
Mecki
+19  A: 

Look up the access() function. You can replace your function with

if( access( fname, F_OK ) != -1 ) {
    // file exists
} else {
    // file doesn't exist
}

You can also use R_OK, W_OK, and X_OK in place of F_OK to check for read permission, write permission, and execute permission (respectively) rather than existence, and you can OR any of them together (i.e. check for both read and write permission using R_OK|W_OK)

Update: Note that on Windows, you can't use W_OK to reliably test for write permission, since the access function does not take DACLs into account. access( fname, W_OK ) may return 0 (success) because the file does not have the read-only attribute set, but you may still have permission to write to the file.

Graeme Perrow
Let me be picky :) access() is not a standard function. If "cross platform" is to be taken in the broader sense, this may fail :)
Remo.D
Define "standard function". Are there platforms where it does not exist?
Graeme Perrow
"standard function" == "included in the ISO standard". A compiler may decide not to have it in its standard library. I can't offer you an example of a compiler that doesn't have it but how can you be sure that every compiler does it?
Remo.D
I can't. I didn't know it was not in the standard. I checked on Windows, Linux, and Mac and it was in all three, so I figured it was everywhere important. :-)
Graeme Perrow
POSIX is an ISO standard; it defines access(). C is another ISO standard; it does not.
Jonathan Leffler
There are pitfalls associated with access(). There is a TOCTOU (time of check, time of use) window of vulnerability between using access() and whatever else you do afterwards. [...to be continued...]
Jonathan Leffler
[...continuing...] Rather more esoterically, on POSIX systems, access() checks whether the real UID and real GID, rather than the effective UID and effective GID. This only matters to setuid or setgid programs, but then it matters intensely as it may give the 'wrong' answer.
Jonathan Leffler
"On success, zero is returned" (man 2 access)If file exists, access return 0.if(0) { file_exist } else { doesn't exists } ???
ofaurax
Thanks ofaurax - fixed!
Graeme Perrow
Jonathan Leffler is right...this answer is wrong.
Randy Proctor
+9  A: 

Use stat like this:

int file_exist (char *filename)
{
  struct stat   buffer;   
  return (stat (filename, &buffer) == 0);
}
codebunny
A: 

From the Visual C++ help, I'd tend to go with

/* ACCESS.C: This example uses _access to check the
 * file named "ACCESS.C" to see if it exists and if
 * writing is allowed.
 */

#include  <io.h>
#include  <stdio.h>
#include  <stdlib.h>

void main( void )
{
   /* Check for existence */
   if( (_access( "ACCESS.C", 0 )) != -1 )
   {
      printf( "File ACCESS.C exists\n" );
      /* Check for write permission */
      if( (_access( "ACCESS.C", 2 )) != -1 )
         printf( "File ACCESS.C has write permission\n" );
   }
}

Also worth noting mode values of _accesss(const char *path,int mode)

00 Existence only

02 Write permission

04 Read permission

06 Read and write permission

As your fopen could fail in situations where the file existed but could not be opened as requested.

Edit: Just read Mecki's post. stat() does look like a neater way to go. Ho hum.

Shane MacLaughlin
access is preffered if you only need to know if the file exists. Stat() can have a large overheard.
Martin Beckett
+3  A: 

Usually when you want to check if a file exists, it's because you want to create that file if it doesn't. Graeme Perrow's answer is good if you don't want to create that file, but it's vulnerable to a race condition if you do: another proces could create the file in between you checking if it exists, and you actually opening it to write to it. (Don't laugh... this could have bad security implications if the file created was a symlink!)

If you want to check for existence and create the file if it doens't exist, atomically so that there are no race condtiions, then use this:

#include <fcntl.h>
#include <errno.h>

fd = open(pathname, O_CREAT | O_WRONLY);
if (fd < 0) {
  /* failure */
  if (errno == EEXIST) {
    /* the file already existed */
    ...
  }
} else {
  /* now you can use the file */
}
Dan
If you are going to use O_CREAT, you need to supply the mode (permissions) as the third argument to open(). Also consider whether O_TRUNC or O_EXCL or O_APPEND should be used.
Jonathan Leffler
Jonathan Leffler is right, this example requires O_EXCL to work as written.
Randy Proctor
A: 

windows: _access function is in "io.h" it's really effing hard to google

pomeroy