2

The way I'm using just involves trying to fopen() the file to be checked,

/* --- does file exist??? --- */ char fname[999] = "whatever"; /* constructed during execution */ FILE *fp = NULL; /* try to fopen(fname,"r") */ int isfilefound = 0; /* set true if fopen() succeeds */ if ( (fp = fopen(fname,"r")) /* try to fopen() for read */ != NULL ) { /* succeeded */ isfilefound = 1; /* set file found flag */ fclose(fp); } /* and just close the file */ 

Is there a quicker, less resource-intensive, way?... A specific way for unix/linux? A Windows way? And preferably, a portable posix-compliant way (as above presumably is)? It's being done lots (1000's) of times, so I'd prefer not to be unnecessarily opening and closing files for no good reason.

-----------------------------------------------------------------
Edit Okay, based on answers below, I put together the following little function intended to check whether or not file (already:) exists in a posix,windows,other portable way...

/* ========================================================================== * Function: isfilexists ( path ) * Purpose: check whether file at path exists * -------------------------------------------------------------------------- * Arguments: path (I) pointer to null-terminated char string * containing "path/filename.ext" of * file whose existence is to be determined * (path is relative to pwd unless explicitly * absolute by initial '/' or other syntax) * -------------------------------------------------------------------------- * Returns: ( int ) 1 if file at path exists, or 0 if not * -------------------------------------------------------------------------- * Notes: o conditional compiles for various systems, * depending on whether POSIX or WINDOWS is #define'ed... * o ...method used: * 1: use access() on Posix systems, * 2: PathFileExists() on Windows systems, * 3: fopen() on any other systems. * ======================================================================= */ /* --- entry point --- */ int isfilexists ( char *path ) { /* --- * allocations and declarations * ------------------------------- */ int isexists = 0; /* set true if file at path exists */ FILE *fp = NULL; /* fopen() for non-posix,windows */ #define POSIX /* just for testing */ /* --- * determine whether file at path already exists * ------------------------------------------------ */ #if defined(POSIX) /* posix-compliant system... */ #include <unistd.h> if ( access(path,F_OK) == 0 ) /* file at path exists */ isexists = 1; /* so set file exists flag */ #else #if defined(WINDOWS) /* Windows system... */ isexists = PathFileExists(path); /* set flag if file at path exists */ #else /* --- fopen() for any other non-posix, non-windows system --- */ if ( (fp = fopen(path,"r")) /* try to fopen() for read */ != NULL ) { /* succeeded */ isexists = 1; /* set file exists flag */ fclose(fp); } /* and just close the file */ #endif #endif return ( isexists ); /* back to caller with 1 if file at path exists */ } /* --- end-of-function isfilexists() --- */ 

The access() and fopen() methods tested and work okay. Unable to test PathFileExists() for windows. And I still want to figure out what #define'ed symbols to automatically and unambiguously check for conditional compiles.

6
  • 4
    There are other ways, e.g. on a POSIX system access() or stat(). But the question is: why do you want to do this check? Checking for existence of the file is quite often the wrong approach. Commented Jun 24, 2017 at 22:01
  • @FelixPalmen I think you could post that as an answer. Commented Jun 24, 2017 at 22:03
  • Thanks, @FelixPalmen I'll definitely try that replacement (post as an answer if you'd like a "check":). Reason is as described in previous question at stackoverflow.com/questions/44719626 (and if you've got a better way, I'm all ears -- post it there for two "checks":) Commented Jun 24, 2017 at 22:06
  • @MartinR ...Oh, yeah. That would be an exact duplicate, no "possibly" about it. I didn't notice that as a suggested answer while writing the question. Not sure whether I just missed it (and I did look at the changing list as I was writing), or if it just strangely wasn't suggested at all. Thanks. Commented Jun 24, 2017 at 22:09
  • @MartinR Then I must have missed it, though I did look at the list of suggested answers while writing, and that question seems >>very obviously<< duplicate. Commented Jun 24, 2017 at 22:15

2 Answers 2

5

You are thinking about the problem the wrong way. You shouldn't ever "check whether a file already exists", because that has an inherent TOCTOU race — in between the time you check whether the file exists, and the time you act on that information, another process may come along and change whether the file exists, rendering the check invalid.

What you do instead depends on why you want to know. One very common case is that you only want to create the file if it doesn't already exist, in which case you use the lower-level open function in O_EXCL mode:

int fd = open("whatever", O_WRONLY|O_CREAT|O_EXCL, 0666); if (fd == -1 && errno == EEXIST) { /* the file already exists */ } else if (fd == -1) { /* report that some other error happened */ } else { FILE *fp = fdopen(fd, "w"); /* write data to fp here */ } 

Another very common case is that you want to create the file if it doesn't exist, or append new data to the file if it does; this can be done with the "a" mode to fopen or O_APPEND flag to open.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, zwoi. Goofy and hard-to-guess reason "why you [I] want to know" is described at stackoverflow.com/questions/44719626 (too long to reproduce on a comment). Briefly, I want browsers to client-side cache <img>'s generated by a server-side script. But running the script from a tag makes the browser think it's a dynamic tag, and the returned data doesn't get client-side cached. That preceding link describes one (overly elaborate) solution involving the check-if-exists question I'm asking here. Thanks again.
@JohnForkosh I think your question has been answered that is why you marked it. If you want to ask another question or want solutions to another question i suggest you don't do that in a comment. Is either you want for your other question to be answered or you add a Bounty on it if is that serious. This is how SO works
@SeekAddo I wasn't asking another question -- as you say, all my questions (except the one about winning lottery numbers) have already been answered. I was just clarifying to zwoi why I asked it in the first place. He went to lots of effort explaining why I probably shouldn't be doing what I was doing, so I just wanted to clarify the unusual reason why I was doing it, and why it should be done in this situation. And anyway, I'm not even seeing anything that could be interpreted as "another question" in my preceding comment.
@JohnForkosh Unfortunately, I don't know enough about HTTP and caching to answer your other question, but I have to believe there's a simpler approach.
@zwoi Yeah, it seems there actually may be a simpler approach -- involving using PATH_INFO environment variable rather than query_strings, and possibly etag's en.wikipedia.org/wiki/HTTP_ETag and similar stuff. I wrote some small tests, and they work at avoiding query_strings, but the browser's still treating them as dynamic tags, at least with everything I've tried. But I'm still hoping that'll somehow eventually work.
4

On Windows, there is PathFileExists().

On a POSIX system, you have stat() or access().

That said, if you check for existence of the file because your code needs the file, this is the wrong approach -- file systems are out of your program's control, so this would be a race condition, the only correct way would be to properly handle errors when opening the file.

5 Comments

Thanks, Felix (I'll "check" shortly -- tried just now, but it said "you can accept in 4 minutes"). But situation's "goofier" than you're thinking, and I'm not seeing any alternative. Check that link stackoverflow.com/questions/44719626 for details.
@JohnForkosh uhm why not do image generation and returning the filename in the same program? You could just use open() with O_WRONLY (on POSIX) and if it succeeds, write your image data (if not, the file was already there, check for errno==EEXIST to be sure) before returning the cached name ...
Yeah, that's what the server-side cgi program is actually doing already. But running any server-side program requires a dynamic tag, in which case the browser never caches the returned data on the client side. So the filenames returned by this little program are never cached either, but that's only a few dozen bytes which are re-downloaded time-after-time. But running the image-generation program and not caching the returned image data means re-downloading many MB's time-after-time.
@JohnForkosh I don't get the problem. You're generating the IMG url with a script, right? so this script could just call your C program that returns the filename and, if the file doesn't exist yet, creates it?
Oh, yeah, then that's pretty much exactly what the script already does -- it's just factored/decomposed slightly differently. With your factoring I always need two tags -- (a) first a dynamic tag to return the filename (and generate it if it doesn't already exist), and then (b) a static tag with src="filename" to download and locally cache the now-guaranteed-to-exist filename. I'm doing it with one tag by just (a) first curl_exec()'ing a short program to check whether the file already exists, and then (b) php-echo'ing either a static tag if it exists, or a dynamic tag if not. Six-of-one, etc.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.