Reputation: 109
Coming from the VB6 era, I was able to use the "on error resume next" in a relatively appropriate manner when recursing through directories on my system. If my "foreach" loop encountered a Permission Denied or Access Denied error, all I had to do was call the "resume next" statement.
In C# however, this does not exist and I appreciate why. However, it boggles my mind to figure out how this is possible in C#.
I am trying to recurse through the directories on my hard drive and populate a TreeView control.
private void PopulateTree(string dir, TreeNode node)
{
try
{
// get the information of the directory
DirectoryInfo directory = new DirectoryInfo(dir);
// loop through each subdirectory
foreach (DirectoryInfo d in directory.GetDirectories("*", SearchOption.AllDirectories))
{
// create a new node
TreeNode t = new TreeNode(d.Name);
// populate the new node recursively
PopulateTree(d.FullName, t);
node.Nodes.Add(t); // add the node to the "master" node
}
// lastly, loop through each file in the directory, and add these as nodes
foreach (FileInfo f in directory.GetFiles())
{
// create a new node
TreeNode t = new TreeNode(f.Name);
// add it to the "master"
node.Nodes.Add(t);
}
}
catch (System.Exception e)
{
MessageBox.Show(e.Message, "Error Loading Directories", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
The code is expected to work. However, the very moment it reaches the "C:\\Documents and Settings"
folder on a Windows 7 machine, the catch block traps the "Access Denied" error (which I expect). What I would like to do is CONTINUE on with the next folder in series.
So the question is, how can I make this possible in C#?
My research shows a common opinion to use a TRY...CATCH block, but it doesn't show me how to do something so simple as what I am wanting to do above.
NOTE: I also try modifying the code to check the attributes as follows but it too fails.
private void PopulateTree(string dir, TreeNode node)
{
try
{
// get the information of the directory
DirectoryInfo directory = new DirectoryInfo(dir);
if (directory.Attributes == FileAttributes.ReparsePoint || directory.Attributes == FileAttributes.System)
{
Console.Write("Access denied to folder.");
}
else
{
// loop through each subdirectory
foreach (DirectoryInfo d in directory.GetDirectories("*", SearchOption.AllDirectories))
{
// create a new node
TreeNode t = new TreeNode(d.Name);
// populate the new node recursively
PopulateTree(d.FullName, t);
node.Nodes.Add(t); // add the node to the "master" node
}
// lastly, loop through each file in the directory, and add these as nodes
foreach (FileInfo f in directory.GetFiles())
{
// create a new node
TreeNode t = new TreeNode(f.Name);
// add it to the "master"
node.Nodes.Add(t);
}
}
}
catch (System.Exception e)
{
MessageBox.Show(e.Message, "Error Loading Directories", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
Upvotes: 4
Views: 21485
Reputation: 1259
For this particular instance (the find files case), I have a work around that avoids the resume after exception problem (see below).
The problem is that GetFiles()/GetDirectories() or EnumerateFiles().GetEnumerator() forces evaluation of the Enumerable, and thus causes the exception to be thrown at that point.
see https://stackoverflow.com/a/9831340/89584 for a code example.
Upvotes: 0
Reputation: 160852
I think your method of choosing sub-directories is flawed, that's why you get the access exceptions - you have to exclude system directories, so something like this should work:
var subDirectories = directory.GetDirectories()
.Where(d => (d.Attributes & FileAttributes.ReparsePoint) ==0
&& (d.Attributes & FileAttributes.System) == 0);
foreach (DirectoryInfo d in subDirectories)
{
//...
}
In your version using directory.GetDirectories("*", SearchOption.AllDirectories)
you specifically ask for system directories to be included - SearchOption.AllDirectories
will include system directories and reparse points. From MSDN:
The weakness in this approach is that if any one of the subdirectories under the specified root causes a DirectoryNotFoundException or UnauthorizedAccessException, the whole method fails and returns no directories. The same is true when you use the GetFiles method. If you have to handle these exceptions on specific subfolders, you must manually walk the directory tree, as shown in the following examples.
Upvotes: 4
Reputation: 15242
Instead of Try-Catching around the whole thing why not do it just where you need it to be.
private void PopulateTree(string dir, TreeNode node)
{
// get the information of the directory
DirectoryInfo directory = new DirectoryInfo(dir);
// loop through each subdirectory
foreach (DirectoryInfo d in directory.GetDirectories("*", SearchOption.AllDirectories))
{
try
{
// create a new node
TreeNode t = new TreeNode(d.Name);
// populate the new node recursively
PopulateTree(d.FullName, t);
node.Nodes.Add(t); // add the node to the "master" node
}
catch (System.Exception e)
{
MessageBox.Show(e.Message, "Error Loading Directories", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
// lastly, loop through each file in the directory, and add these as nodes
foreach (FileInfo f in directory.GetFiles())
{
// create a new node
TreeNode t = new TreeNode(f.Name);
// add it to the "master"
node.Nodes.Add(t);
}
}
Upvotes: 0
Reputation: 61437
Move the try/catch block into the foreach loop, so you have the populating code in the try block. That way, you don't drop out of the loop when an exception is encountered.
foreach(var item in col)
{
try
{
//do stuff with item
}
catch
{
//yes, this is empty, but in this case it is okay as there is no other way
}
}
Upvotes: 7