3

The member function DirectoryInfo::EnumerateFiles can throw only DirectoryNotFoundException and SecurityException

whereas the static function Directory::EnumerateFiles can throw same exceptions plus many others ones like PathTooLongException, UnauthorizedAccessException, IOException

Why?

I need to write robust code. What is the best way to handle exceptions when iterating on files in a directory in C#?

Mike Perrenoud
  • 66,820
  • 29
  • 157
  • 232
sthiers
  • 3,489
  • 5
  • 34
  • 47
  • See also http://stackoverflow.com/questions/3146586/directory-vs-directoryinfo?rq=1 – RvdK Jul 19 '13 at 12:41
  • http://stackoverflow.com/questions/13130052/directoryinfo-enumeratefiles-causes-unauthorizedaccessexception-and-other – MethodMan Jul 19 '13 at 12:43

3 Answers3

2

The reason is because of the way they're used. DirectoryInfo::EnumerateFiles works on the current directory, so by its nature, the effort of getting the directory loaded into the object is already done - the worrying about path too long etc. is done by the construction of the DirectoryInfo object, eg:

DirectoryInfo di = new DirectoryInfo(...); // Gets the directory - many things could go wrong here

di.EnumerateFiles(); // Since we have a DirectoryInfo object, we already know the directory is ok - we've checked for the other problems already.

Directory.EnumerateFiles is a static method, which means it doesn't work on an existing object that's already been successfully created. Therefore it has to load the directory (which could cause any number of exceptions), and THEN enumerate the files.

It's essentially the top two steps combined into one.

Another way of looking at it, in English, would be:

  • Load this directory into an object for me c:\myfolder

DirectoryInfo myObject = new DirectoryInfo(@"C:\myfolder");

If it's not valid eg. because the path is too long, you'll get an exception here.

If it works, it's now loaded information about the directory into the object. So you can say

  • Hey, that directory I loaded - enumerate the files on it for me.

myObject.EnumerateFiles();

Since it's loaded the folder already, it doesn't need to do it again because it knows it's working and completely fine. The only possibilities are not found (if between these two lines, you delete the folder on your computer) and a SecurityException which is that you don't have permission to enumerate.

The other example combines those two steps, and says "Enumerate all the files in this folder for me"

So it will load the folder (which could generate all those exceptions) and then enumerate the files, all in a single step.

Some information about PathTooLongException:

The maximum length you can have for a file including the full path is 260 characters. Therefore if you have a folder like c:\aaaaaaaaaaaaaaaaa..... that is 250 characters long, you might think by putting a file that is 20 characters long into the folder (for a total of 270) would cause the DirectoryInfo to throw an exception.

However it's simply not possible to put a file in the folder - windows gives the error:

The file name(s) would be too long for the destination folder.

So it's not possible for DirectoryInfo.EnumerateFiles to be tricked into exceeding the maximum length of 260 because it's impossible to create anything more than 260 characters long.

NibblyPig
  • 51,118
  • 72
  • 200
  • 356
  • Do you mean that "di.EnumerateFiles()" has no reason to throw PathTooLongException, even if di contains deeply nested directories? This looks weird to me. I cannot imagine that the constructor of DirectoryInfo does all these checks, even for nested directories – sthiers Jul 19 '13 at 12:44
  • Correct, because if the path is too long, you won't be able to do the first line of `new DirectoryInfo(...)` and .EnumerateFiles must be performed on the object that you create. – NibblyPig Jul 19 '13 at 12:46
  • What happens with PathTooLong when discovered at enumeration in deeply nested directory? I don't think all possible checks are recursively done by top level DirectoryInfo constructor ?? – sthiers Jul 19 '13 at 13:07
  • An interesting question, I tried it and the answer is, you cannot create a file on your computer that exceeds the total of 260 characters including the filename. Therefore the method will never be in a situation where it throws an error. I've updated my answer to explain more. – NibblyPig Jul 19 '13 at 15:46
  • This is not true, of course file paths can be longer than 260 characters (basic feature of NTFS). Only some tools like Explorer don't support that. Yes, that is no joke. With Windows 10 Explorer supports longer file paths too. Concerning .NET: Until .NET 4.6.2 longer paths were not supported directly (but indirectly they were possible). But here is the .NET 4.6.2 news: They are supported now: https://blogs.msdn.microsoft.com/dotnet/2016/08/02/announcing-net-framework-4-6-2/ – Philm Mar 01 '17 at 16:35
  • NTFS supports more than 260 characters, but windows, including Windows 10, does not support paths longer than 260 by default without a registry edit, including explorer. Try to create one and you'll get a "path too long" error. It (supposedly) supports longer paths by using `\\machine\c\windows` NT style notation but even this is unreliable between applications. – NibblyPig Mar 02 '17 at 10:30
1

The static Directory methods need a parameter for the path to the directory whereas the DirectoryInfo methods are instance methods on an already created DirectoryInfo object. Hence the Directory approach can introduce problems that the DirectoryInfo methods don't have anymore when you call it's methods, like:

  • ArgumentException
  • ArgumentNullException
  • DirectoryNotFoundException
  • PathTooLongException

However, if you have a look at the constructor of DirectoryInfo you'll see that these possible problems are already handled there.

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • What happens if a given DirectoryInfo represents a directory with valid path (ie not too long), but contains one too deeply nested subdirectory? I cannot imagine that the check for PathTooLong is done recursively for all contained subdirs? – sthiers Jul 19 '13 at 13:04
0

It can throw more exceptions because it's handling the construction and destruction of the objects used to perform it in one call.

What is the best way to handle exceptions when iterating on files in a directory in C#?

How you handle them is up to you, but unless the exception means something to you specifically and you're going to do something different because of it, then just do this:

try
{
    ...
}
catch (Exception ex)
{
    ...
}

That will catch all of them.

If you want to handle each of them it would look like this:

try
{
}
catch (DirectoryNotFoundException ex)
{
}
catch (SecurityException ex)
{
}
etc...
Mike Perrenoud
  • 66,820
  • 29
  • 157
  • 232