Farukh Farukh - 26 days ago 4
C# Question

Directory.CreateDirectory fails with invalid character

I am facing issue that my path string passes check for Path.GetInvalidPathChars() but fails when trying to create directory.

static void Main(string[] args)
{

string str2 = @"C:\Temp\hjk&(*&ghj\config\";

foreach (var character in System.IO.Path.GetInvalidPathChars())
{
if (str2.IndexOf(character) > -1)
{

Console.WriteLine("String contains invalid path character '{0}'", character);
return;
}
}


Directory.CreateDirectory(str2); //<-- Throws exception saying Invalid character.

Console.WriteLine("Press any key..");
Console.ReadKey();
}


Any idea what could be the issue?

Answer

This is one of those times where slight issues in the wording of the documentation can make all the difference on how we look at or use the API. In our case, the API doesn't do us any good.


You haven't completely read the documentation on Path.GetInvalidPathChars():

The array returned from this method is not guaranteed to contain the complete set of characters that are invalid in file and directory names. The full set of invalid characters can vary by file system. For example, on Windows-based desktop platforms, invalid path characters might include ASCII/Unicode characters 1 through 31, as well as quote ("), less than (<), greater than (>), pipe (|), backspace (\b), null (\0) and tab (\t).

And don't think that Path.GetInvalidFileNameChars() will do you any better:

The array returned from this method is not guaranteed to contain the complete set of characters that are invalid in file and directory names. The full set of invalid characters can vary by file system. For example, on Windows-based desktop platforms, invalid path characters might include ASCII/Unicode characters 1 through 31, as well as quote ("), less than (<), greater than (>), pipe (|), backspace (\b), null (\0) and tab (\t).


In this situation, it's best to try { Directory.CreateDirectory(str2); } catch (ArgumentException e) { /* Most likely the path was invalid */ } instead of manually validating the path*. This will work independent of file-system.

When I tried to create your directory on my Windows system:

Invalid Path Characters

Now if we go through all the characters in that array:

foreach (char c in Path.GetInvalidPathChars())
{
    Console.WriteLine($"0x{(int)c:X4} : {c}");
}

We get:

0x0022 : "
0x003C : <
0x003E : >
0x007C : |
0x0000 : 
0x0001 : 
0x0002 : 
0x0003 : 
0x0004 : 
0x0005 : 
0x0006 : 
0x0007 : 
0x0008 : 
0x0009 :   
0x000A : 

0x000B : 
0x000C : 
0x000D : 
0x000E : 
0x000F : 
0x0010 : 
0x0011 : 
0x0012 : 
0x0013 : 
0x0014 : 
0x0015 : 
0x0016 : 
0x0017 : 
0x0018 : 
0x0019 : 
0x001A : 
0x001B : 
0x001C : 
0x001D : 
0x001E : 
0x001F : 

As you can see, that list is incomplete.

However: if we do the same for GetInvalidFileNameChars()

foreach (char c in Path.GetInvalidFileNameChars())
{
    Console.WriteLine($"0x{(int)c:X4} : {c}");
}

We end up with a different list, which includes all of the above, as well as:

0x003A : :
0x002A : *
0x003F : ?
0x005C : \
0x002F : /

Which is exactly what our error-message indicates. In this situation, you may decide you want to use that instead. Just remember our warning above, Microsoft makes no guarantees as to the accuracy of either of these methods.

*: This is arguable, you may want to manually validate the path if you are certain your validation code will not invalidate valid paths. As MikeT said: "you should always try to validate before getting an exception".