4

So what is better? To use construction like this:

if (File.Exist(fileName))
{
    // do something with file...
}

of just

try 
{
    // do something with file.
}
catch(Exception ex)
{
}

Does it cost a lot to use method File.Exist()?

Thank you!

NoWar
  • 36,338
  • 80
  • 323
  • 498
  • 3
    `catch(FileNotFoundException ex)`, surely? –  Nov 23 '12 at 12:23
  • If you're 102% sure that the File will exist for eternity, then you can ignore the check. – Sandeep Nov 23 '12 at 12:27
  • Surely you should also be asking how much it costs to use a try/catch block? I've been led to believe they are expensive and so should be avoided when possible. From this point of view use `File.Exist`. If it is in fact quicker to use a try catch while doing something with the file then you can probably assume that they will have written `File.Exist` this way. – Chris Nov 23 '12 at 12:28
  • 1. If you expect the file might not exist then the case isn't exceptional and you should probably check using File.Exists. 2. How long would it actually take you to knock up a simple console application to do the measurements yourself? Here's a start for (int i = 0 ; i < 1000; i++){} – BenCr Nov 23 '12 at 12:28
  • `File.Exists` never throws an exception. – leppie Nov 23 '12 at 12:34

5 Answers5

11

The former has a race condition: another process may remove the file after File.Exists has returned true, but before you open it. The latter does not. Even if you check beforehand, you should still catch an exception if you want to ignore nonexistant files.

So it should be either

if (File.Exists(fileName))
{
    try
    {
        // ...
    }
    catch (FileNotFoundException)
    { }
}

or

try
{
    // ...
}
catch (FileNotFoundException)
{ }

The former duplicates the check, which could be slow if the file is on a network share, the latter raises an exception (which gets handled) for a non-exceptional condition, complicating debugging. Both have their merits. Personally, I generally opt for the second, but either is okay.

  • I think Microsoft have removed the ability to do File.Exists checks from the WinRT APIs for this reason. – BenCr Nov 23 '12 at 12:32
  • In the first case, you now have two possibilities when a file does not exist. If it doesn't exist before entering the `if` block, what do you do? `throw new FileNotFoundException()`? – CodeCaster Nov 23 '12 at 12:34
  • +1 for noting the classic filesystem race conditions. Mono's version of MSBuild is littered with them... – leppie Nov 23 '12 at 12:35
  • @CodeCaster There are cases when nonexistant files should just be ignored silently, I've assumed this question is one of them because the code in the question does just that (note how there's nothing in the `catch` block). So if it doesn't exist before entering the `if` block, `File.Exists` returns false, and the block gets skipped. No problem. –  Nov 23 '12 at 12:36
  • It is a problem, because I meant if it gets removed while inside the if but before opening it (the race condition), the code will throw the `FileNotFoundException`. So you'll have two possibilities. Please try to implement it in a method, then you'll see what I mean. The calling code will want to know what happened, so you'll have to either return something or throw an exception, and you don't want to use both for the same situation (i.e. a non-existant file). So _if_ you're going to throw an exception anyway, the `if` is useless. – CodeCaster Nov 23 '12 at 12:39
  • @CodeCaster In that case, `FileNotFoundException` will be thrown, caught, and ignored, giving the same result as if `File.Exists` returned false in the first place. "The calling code will want to know what happened" That's what I disagree with. If the code is supposed to do nothing when the file doesn't exist, it's correct that it just returns normally without an error code or exception, is it not? –  Nov 23 '12 at 12:55
  • _"If the code is supposed to do nothing when the file doesn't exist"_ - that is very rarely the case, I was talking about the more general case (see also my updated answer). But then still - the `if` will be useless, since not having the `if` will have the exact same result. Minus one filesystem roundtrip. – CodeCaster Nov 23 '12 at 12:56
  • @CodeCaster In that case, sure, if we start with different assumptions, we will come to different conclusions. :) If the code does need to indicate that an operation succeeded, something more is needed. About your "But then still" part: as I mentioned in my answer, it complicates debugging. It's generally useful for me to stop when any exception is thrown, not only when an unhandled exception is thrown. But this will lead to plenty of handled exceptions. –  Nov 23 '12 at 13:01
  • It simply depends whether a non-existant file is _"a non-exceptional condition"_. In my experience it usually is exceptional, because the application has a configured path to the file or a user selected a file in some dialog. Given that such constraints aren't mentioned in this question, you are right; but as I said you usually want to know that a file you try to access doesn't exist, and not get `null` or some default back. That being said: the `if` will save you an exception (if not the race case), which might indeed be helpful in debugging. – CodeCaster Nov 23 '12 at 13:13
5

Exceptions are not supposed to be used to handle the flow of your application, the idea is to avoid exceptions and not to expect them as normal part of the execution flow.

For 99.999% of the applications, if there is any performance difference, won't be appreciable. If the file should be there and not finding is a exceptional scenario, you could use the try catch block otherwise I'd say you should go for the File.Exist approach.

Claudio Redi
  • 67,454
  • 15
  • 130
  • 155
  • "Exceptions are not supposed to be used to handle the flow of your application, the idea is to avoid exceptions and not to expect them as normal part of the execution flow." I like it. THANKS!!! – NoWar Nov 23 '12 at 12:32
1

Depends on your program flow and the actions you're performing. If you expect the file to exist, you can rely on exception handling, since your program cannot continue if it doesn't and the exception most probably needs to be handled higher up in the call chain.

Otherwise, you'll get the True|False|FileNotFound return code madness, if the method in question is something like ReadFile().

Using File.Exists to "safely" open a file is pretty useless. Consider this:

public String ReadFile(String filename)
{
    if (!File.Exists(filename))
    {
        // now what? throw new FileNotFoundException()? return null?
    }

    // Will throw FileNotFoundException if not exists, can happen (race condition, file gets deleted after the `if` above)
    using (var reader = new StreamReader(filename))
    {
        return reader.ReadToEnd();
    }
}

One could say you'd want to check if a file exists if you want to append data to it, but the StreamWriter constructor has an overload with an append parameter, which will let the writer create the file if it doesn't exist and append to it if it does.

So, perhaps the question could better be: what valid use cases exist for File.Exists? And luckily that question has already been asked and answered.

Community
  • 1
  • 1
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
0

First I'd check if the file exists and throw an exception if it doesn't exist.

After that I'd use a try-catch block to handle other exceptions that may be thrown (permissions, etc)

if (!File.Exist(fileName))
{
    throw new ArgumentException("filename");
    // or throw new FileNotFoundException("filename");
}


try 
{
    // do something with file.
}
catch(Exception ex)
{
}
Rui Jarimba
  • 11,166
  • 11
  • 56
  • 86
0

The first case-

if (File.Exist(fileName)) //A single statement to check and proceed. 

While the later method of exception handling involves-

An object of the exception class to be created and passed to the corresponding catch block if exception is raised.

I would prefer the first method since using exception handling for handling the flow of execution isn't a good idea.

Shiridish
  • 4,942
  • 5
  • 33
  • 64