3

I want to check if a folder exists and if not then create it. But I don't know if the path supplied will even valid. When the path is not valid the following happens.

string path = "this is an invalid path";

if (!Directory.Exists(path))
    Directory.CreateDirectory(path); //Exception thrown here

If you supply an invalid path, it will throw a DirectoryNotFoundException exception.

How can I stop this exception from occurring? I don't want to use a try-catch. I want to detect that this exception will occur even before the exception happens.

Litisqe Kumar
  • 2,512
  • 4
  • 26
  • 40
user1384603
  • 545
  • 5
  • 12
  • 16
  • 2
    Check this [SO: In C# check that filename is *possibly* valid (not that it exists)](http://stackoverflow.com/questions/422090/in-c-sharp-check-that-filename-is-possibly-valid-not-that-it-exists) – chaliasos Dec 18 '12 at 13:10
  • possible duplicate of [How check if given string is legal (allowed) file name under Windows?](http://stackoverflow.com/questions/62771/how-check-if-given-string-is-legal-allowed-file-name-under-windows) – nawfal Jun 05 '13 at 11:53

7 Answers7

10

Use Directory.Exists method to check if a folder exists

if(Directory.Exists(path))
{
  //Directory exists
}
else
{
 // doesn't exist
}

Remember to include System.IO;

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
Habib
  • 219,104
  • 29
  • 407
  • 436
8

The explanation for the failure of your code is that the path is invalid. The documentation says:

DirectoryNotFoundException

The specified path is invalid (for example, it is on an unmapped drive).

Trying to predict in advance whether or not a directory can be created is a devil of a job. You'd need to account for security, OS name rules and limits, file system name rules and limits, and whether or not drives are mapped. And probably lots more concerns. I would not contemplate re-implementing what the system provides for free.

In any case, whilst you can call Directory.Exists, you do still need to allow for an exception being thrown. If the file system changes between the call to Directory.Exists and the subsequent call to Directory.CreateDirectory, then an exception will be raised. For example, if another process creates the directory that you are trying to create. Granted, this is a rather unlikely event, but it's perfectly possible.

In summary, the best option, by a distance, is to catch the exception. As the well known saying goes, it's better to ask for forgiveness than to ask for permission.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
3

Why don't you want to catch (specific) Exceptions? It is considered as a good practice... anyway, these are my solutions without try/catch:

  1. solution:

    string path = "C:\test";
    if (!Directory.Exists(path) && path.IndexOfAny(Path.GetInvalidFileNameChars()) == -1)
    {
        Directory.CreateDirectory(path);
    }
    
  2. solution:

    string path = "C:\test";
    var canCreate = true;
    foreach (var c in path.Where(Path.GetInvalidFileNameChars().Contains))
    {
        canCreate = false;
    }
    
    if (canCreate && !Directory.Exists(path))
    {
        Directory.CreateDirectory(path);
    }
    
  3. solution:

    if (path.Any(c => Path.GetInvalidFileNameChars().Contains(c)) && !Directory.Exists(path))
    {
        Directory.CreateDirectory(path);
    }
    

Please, be aware that this code can still fail... e.g. think about SecurityExeption (do you have the credentionals to create a directory there?!?

Also be aware there is still a (little) chance that the directory has been created (by another process/thread/...) after your test with Exists() but before your call of CreateDirectory(). These are two calls and they are not atomic (together) when querying/modifying the file system.

Beachwalker
  • 7,685
  • 6
  • 52
  • 94
  • Using exceptions for flow control is definitely not good practice (http://softwareengineering.stackexchange.com/a/189225/113496). Unfortunately the .Net framework makes this nearly unavoidable in certain circumstances. – Ian Goldby Jan 10 '17 at 09:13
  • @Ian Goldby Yes, not for flow control. But he is asking for IO and a safe operation and is considered best practice here to catch specific Exceptions and maybe wrap it in own exceptionless IO-Methods if he want it that way. Anyway, it is not a huge work-/control flow here and I don't see the benefit of not simply catching the exception here and doing it the way it is typical in C# and doing it in a "different" way without the need to do so. The thing he is asking for is not possible (afaik), the check is not atomic. So why not just catch and just go on with the real important logic? – Beachwalker Jan 17 '17 at 12:52
  • @Ian Goldby It is about just simply accept the fact it is not atomic and queried result is stale and might not be correct / same result for the next operations (so with directory check and creation if it not exists). Then catch the (rare?) case and handle it. This should not affect the business logic very much at this low level func. If the exception occurs very often... then you might think about why/what are you doing because it seems a default case and there is something wrong with the "architectural" approach. – Beachwalker Jan 17 '17 at 12:55
  • I think we agree from a pragmatic point of view. I was merely pointing out that just because you are forced by .NET to use exceptions for flow control it does not make it 'best practice'. (It's more a necessary evil, mitigated very slightly by catching only specific exceptions.) – Ian Goldby Jan 17 '17 at 14:05
0

You can also use Path.GetInvalidFileNameChars() to check whether the directory name supplied is valid for a new directory name:

// Directory.Exists will return false because path is not even valid
var path = "1:1 comparison?";
var firstBad = Path.GetInvalidFileNameChars().Cast<char?>()
                   .FirstOrDefault(c => path.Contains(c.Value));
if (firstBad != null)
    Console.WriteLine("Char '{0}' is invalid for a directory name", firstBad.Value);
Joshua Honig
  • 12,925
  • 8
  • 53
  • 75
0

try this

string path = "this is an invalid path";

        if (Path.IsPathRooted(path)
        {
            Directory.CreateDirectory(path); 
        }
Akshita
  • 849
  • 8
  • 15
  • The question asked how to avoid raising an exception if the path is invalid, but `IsPathRooted` raises an exception if path contains one or more of the invalid characters defined in `GetInvalidPathChars`. – Ian Goldby Jan 10 '17 at 09:10
0

I think the simplest way to test if a path is valid and the file exists without raising an exception in C# is to call the unmanaged function PathFileExists directly in shlwapi.dll.

[DllImport("shlwapi.dll", EntryPoint = "PathFileExistsW",  SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool PathFileExists([MarshalAs(UnmanagedType.LPTStr)]string pszPath);

Note that as David writes in his answer, you might nevertheless get an exception when you try to create the directory.

Community
  • 1
  • 1
Ian Goldby
  • 5,609
  • 1
  • 45
  • 81
-1

You can use a single if-else statement

if(!Directory.Exists(path))
   Directory.CreateDirectory(path)
else
   //Show user a custom error message
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Marlon Vidal
  • 669
  • 4
  • 14