Why does try catch error in recursive function C# - c#

I've created a function used to populate a treeview with a targeted directory. However when I try to implement and error check to skip over folders which may have folder permission restrictions I get an error. Why do I get this error and how do i fix it?
Thank you in advance.
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace directoryBrowser
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
ListDirectory(treeView1, #"C:\Windows");
}
public void ListDirectory(TreeView treeView, string path)
{
treeView.Nodes.Clear();
var rootDirectoryInfo = new DirectoryInfo(path);
treeView.Nodes.Add(CreateDirectoryNode(rootDirectoryInfo));
}
public static TreeNode CreateDirectoryNode(DirectoryInfo directoryInfo)
{
//try
//{
var directoryNode = new TreeNode(directoryInfo.Name);
foreach (var directory in directoryInfo.GetDirectories())
{
directoryNode.Nodes.Add(CreateDirectoryNode(directory));
}
foreach (var file in directoryInfo.GetFiles())
{
directoryNode.Nodes.Add(new TreeNode(file.Name));
}
return directoryNode;
//}
//catch (UnauthorizedAccessException) { }
}
}
}

You are answering your own question. You get an error because the user account which this function is running under doesn't have permission to access some of the folder.
You should then apply a try/catch statement WITHIN the for loop so if you get this exception, you function will keep on running for following folders.
public static TreeNode CreateDirectoryNode(DirectoryInfo directoryInfo)
{
var directoryNode = new TreeNode(directoryInfo.Name);
foreach (var directory in directoryInfo.GetDirectories())
{
//try
{
directoryNode.Nodes.Add(CreateDirectoryNode(directory));
} catch {
// cannot access directory
}
}
foreach (var file in directoryInfo.GetFiles())
{
directoryNode.Nodes.Add(new TreeNode(file.Name));
}
return directoryNode;
}

Related

How to continue from a UnauthorizedAccessException error in c# when searching for files

I am trying to figure out how to continue from a UnauthorizedAccessException error. I am trying to list all files in my drives and have used the try/ctch statements and continue but nothing seems to work.
Here is the code:
using System;
using System.IO;
using System.Linq;
public class Program
{
public static void Main(string[] args)
{
foreach(DriveInfo d in DriveInfo.GetDrives().Where(x = > x.IsReady))
{
try
{
string[] files = Directory.GetFiles(d.RootDirectory.FullName, #"*.*", SearchOption.AllDirectories).ToArray();
foreach(string file in files)
{
Console.Write(file);
}
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine(e.Message);
continue;
}
}
}
}
The exeception catches that I cannot access 'C:\Documents and Settings' but then terminates the code instead of listing the rest of the files that I can access. I have read up and know this is a problem/bug with net but cannot find out how to continue even after catching the exception.
You need to use recursion to query one directory at a time. This way you can catch any unauthorized exceptions and continue your search.
static void Main()
{
foreach (DriveInfo info in DriveInfo.GetDrives().Where(c => c.IsReady))
{
foreach (string file in DirSearch(info.RootDirectory.FullName))
{
Console.WriteLine(file);
}
}
Console.ReadKey(true);
}
private static IList<string> DirSearch(string path)
{
List<string> files = new List<string>();
try
{
foreach (string dir in Directory.GetDirectories(path))
{
foreach (string file in Directory.GetFiles(dir))
{
files.Add(file);
}
files.AddRange(DirSearch(dir));
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return files;
}

Most efficient way (if exists) to get array of files in root

I want to get all files (recursively) in my root directory / of linux OS.
I am using the following code
var files = System.IO.Directory.GetFiles("/", "*", SearchOption.AllDirectories);
But its taking so much time which is making my code inefficient. Is there any way to find files recursively in much more efficient way ?
I thought of this answer but again its taking even more time than System.IO.Directory.GetFiles()
I think Matthew Watson is right, whatever you do is going to work slowly because of the disc. The only thing I would try to do is do it parallely. If you have other things to do while waiting on result, maybe async is a good choiche.
using System;
using System.Threading.Tasks;
using System.IO;
using System.Collections.Concurrent;
namespace Test
{
class Program
{
static void Main(string[] args)
{
GetFilesOnRoot("*");
Console.ReadLine();
}
private static ConcurrentBag<string> FilesBag;
private static void GetFilesOnRoot(string filter)
{
FilesBag = new ConcurrentBag<string>();
DirectoryInfo dirRoot = new DirectoryInfo("/");
GetDirTree(dirRoot, "*");
}
private static void GetDirTree(DirectoryInfo dr, string filter)
{
FileInfo[] files = null;
DirectoryInfo[] subDirs = null;
try
{
files = dr.GetFiles(filter + ".*");
}
catch(Exception) { }
if (files != null)
{
Parallel.ForEach(files, (FileInfo item) => { FilesBag.Add(item.Name); });
subDirs = dr.GetDirectories();
Parallel.ForEach(subDirs, (DirectoryInfo item) => { GetDirTree(item,filter); });
}
}
public static async Task GetFilesOnRootAsync(string filter)
{
await Task.Run(() => {
GetFilesOnRoot(filter);
});
}
}
}

How can i ignore access denied when searching to get all sub directories?

static IEnumerable<string> GetSubdirectoriesContainingOnlyFiles(string path)
{
try
{
return from subdirectory in Directory.GetDirectories(path, "*", SearchOption.AllDirectories)
where Directory.GetDirectories(subdirectory).Length == 0
select subdirectory;
}
catch
{
}
}
In this case i'm searching in c:\
So some directories are access denied. I added try and catch but now this method dosent have a return.
And how or should i handle at all it when it's getting to the catch ?
I want in the end to get a List of all sub directories so i can get all sub directories names and the Length(the number of sub directories).
UPDATE
I tried this in the class constructor:
if (m_pars.SearchDir != null)
{
ApplyAllFiles(m_pars.SearchDir,ProcessFile);
}
m_pars.SearchDir in this contain C:\
Then in ApplyAllFiles:
static List<string> allsubdirs = new List<string>();
static void ProcessFile(string path) {/* ... */}
public static void ApplyAllFiles(string folder, Action<string> fileAction)
{
foreach (string file in Directory.GetFiles(folder))
{
fileAction(file);
}
foreach (string subDir in Directory.GetDirectories(folder))
{
try
{
ApplyAllFiles(subDir, fileAction);
allsubdirs.Add(subDir);
}
catch
{
// swallow, log, whatever
}
}
}
But the List allsubdirs is empty.
Your problem might be that you don't visit (add to the list) the current directory before recursively visiting its subdirectories. So if you get an exception there, nothing will be added to the list.
The following works for me. (I've also made it a bit more generic by using callbacks and made the exception handling stricter.)
class DirectoryHelper
{
public static void Test()
{
DirectoryHelper.EnumerateSubDirectories(#"c:\windows\system32");
}
public static List<string> EnumerateSubDirectories(string path)
{
// Depending on your use case, it might be
// unecessary to save these in memory
List<string> allSubdirs = new List<string>();
EnumerateSubDirectories(path,
filePath => Console.WriteLine("Visited file: " + filePath),
dirPath => allSubdirs.Add(dirPath),
noAccessPath => Console.WriteLine("No access: " + noAccessPath)
);
return allSubdirs;
}
private static void EnumerateSubDirectories(string root, Action<string> fileAction, Action<string> subdirAction, Action<string> noAccessAction)
{
foreach (string file in Directory.GetFiles(root))
{
fileAction(file);
}
foreach (string dir in Directory.GetDirectories(root))
{
try
{
subdirAction(dir);
EnumerateSubDirectories(dir, fileAction, subdirAction, noAccessAction);
}
catch (UnauthorizedAccessException)
{
noAccessAction(dir);
}
}
}
}

How to load folder structure into treeview?

I want to Load Directory Structure Into TreeView. If there is a txt file in folder it must be break. Child folders and files should not shown. Please help me to find an algorithm
private void ListDirectory(TreeView treeView, string path)
{
treeView.Nodes.Clear();
var rootDirectoryInfo = new DirectoryInfo(path);
treeView.Nodes.Add(CreateDirectoryNode(rootDirectoryInfo));
}
private static TreeNode CreateDirectoryNode(DirectoryInfo directoryInfo)
{
var directoryNode = new TreeNode(directoryInfo.Name);
foreach (var directory in directoryInfo.GetDirectories())
{
if (directory.Name.EndsWith("txt"))
{
break;
}
else
{
directoryNode.Nodes.Add(CreateDirectoryNode(directory));
}
}
foreach (var file in directoryInfo.GetFiles())
{
if (directoryNode.Name.EndsWith("txt"))
{
directoryNode.Nodes.Add(new TreeNode(file.Name));
}
}
return directoryNode;
}
I solved it like that,
private static TreeNode CreateDirectoryNode(DirectoryInfo directoryInfo)
{
var directoryNode = new TreeNode(directoryInfo.Name);
try
{
int flag = 0;
foreach (var file in directoryInfo.GetFiles())
{
if (file.Name.EndsWith("txt"))
{
flag = 1;
}
}
if (flag == 0)
{
foreach (var directory in directoryInfo.GetDirectories())
{
directoryNode.Nodes.Add(CreateDirectoryNode(directory));
}
}
return directoryNode;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return null;
}
}

Clearing an ObservableCollection after populating it with entries

I have the following code to populate a Treeview with drives (RootDrive) and directories.
But how do I clear the directories collection after each loop? What happens now is that all directories in all drives are added to each drive.
When I use directories.Clear() in the Finally statement there are no directories added to each drive.
static public ObservableCollection<GetDrive> RootDrive = new ObservableCollection<GetDrive>();
public MainWindow()
{
InitializeComponent();
ObservableCollection<GetDirectory>directories = new ObservableCollection<GetDirectory>();
foreach (DriveInfo di in DriveInfo.GetDrives())
{
try
{
foreach (string s in Directory.GetDirectories(di.Name))
{
directories.Add(new GetDirectory(s));
}
}
catch (IOException) //drive is not ready, e.g. DVD drive
{
}
finally
{
RootDrive.Add(new GetDrive(di.Name, directories));
directories.Clear();
}
}
}
}
}
Simply put, use a local variable instead. And you are misusing the finally directive.
static public ObservableCollection<GetDrive> RootDrive = new ObservableCollection<GetDrive>();
public MainWindow()
{
InitializeComponent();
foreach (DriveInfo di in DriveInfo.GetDrives())
{
ObservableCollection<GetDirectory>directories = new ObservableCollection<GetDirectory>();
try
{
foreach (string s in Directory.GetDirectories(di.Name))
{
directories.Add(new GetDirectory(s));
}
}
catch (IOException) //drive is not ready, e.g. DVD drive
{
// Handle it?
}
RootDrive.Add(new GetDrive(di.Name, directories));
}
}
I think you have to change the code bit and add clear method after the first for loop. like below...
static public ObservableCollection<GetDrive> RootDrive = new ObservableCollection<GetDrive>();
public MainWindow()
{
InitializeComponent();
foreach (DriveInfo di in DriveInfo.GetDrives())
{
try
{
directories.Clear();
foreach (string s in Directory.GetDirectories(di.Name))
{
directories.Add(new GetDirectory(s));
}
}
catch (IOException) //drive is not ready, e.g. DVD drive
{
}
finally
{
RootDrive.Add(new GetDrive(di.Name, directories));
}
}
}
}

Categories