I have this recursive method which deletes empty folders:
private void DeleteEmpty(DirectoryInfo directory)
{
foreach (var d in directory.GetDirectories())
{
DeleteEmpty(d);
}
if (directory.GetFileSystemInfos().Length == 0)
{
try
{
directory.Delete();
}
catch (Exception)
{
// Already gone, no permission, not empty, et cetera
}
}
}
How can I refactor this method so that it is not recursive?
The standard refactoring is to store the data you would otherwise be passing to the function in a LIFO (i.e. a stack) or FIFO queue. Note that this doesn't change asymptotic space usage; you're using your own data structure rather than the call stack.
If you can define a "next sibling" function, you can visit the nodes with constant additional space. This is because the graph of directories (sans files) is essentially undirected due to parent pointers. Pseudocode:
nextBranchingSibling(sibling):
while sibling exists
if sibling has children
return sibling
sibling = nextSibling(sibling)
return null
nextBranch(node):
if node is marked
unmark node
else
if nextBranchingSibling(firstChild(node)) exists
return nextBranchingSibling(firstChild(node))
if nextBranchingSibling(nextSibling(node)) exists
return nextBranchingSibling(nextSibling(node))
mark parent(node)
return parent(node)
prune(node):
while node exists:
tmpNode = node
node = nextBranch(node)
if count of tmpNode's children is 0
delete tmpNode
Note that you're not actually using O(1) space total, since the directory structure is itself O(n). Methods like DirectoryInfo.GetDirectories can remove the need for loops in nextBranchingSibling.
private static Queue<DirectoryInfo> directoryQueue = new Queue<DirectoryInfo>();
private void DeleteEmpty(DirectoryInfo directory)
{
directoryQueue.Enqueue(directory);
while (directoryQueue.Count > 0)
{
var current = directoryQueue.Dequeue();
foreach (var d in current.GetDirectories())
{
directoryQueue.Enqueue(d);
}
if (directory.GetFileSystemInfos().Length == 0)
{
try
{
directory.Delete();
}
catch (Exception)
{
// Already gone, no permission, not empty, et cetera
}
}
}
}
Try this:
private void DeleteEmpty(string path)
{
string[] directories = Directory.GetDirectories(
path, "*", SearchOption.AllDirectories);
// you should delete deeper directories first
// .OrderByDescending(
// dir => dir.Split(Path.DirectorySeparatorChar).Length)
// .ToArray();
foreach (string directory in directories)
{
DirectoryInfo info = new DirectoryInfo(directory);
if (info.GetFileSystemInfos().Length == 0)
{
info.Delete();
}
}
// If you wanna a LINQ-ish version
// directories.Where(dir =>
// new DirectoryInfo(dir).GetFileSystemInfos().Length == 0)
// .ToList().ForEach(dir => Directory.Delete(dir));
}
Another performance step could be: if you tried to remove a directory and it contains files, all parent levels should be skipped since they WILL fail too.
You could use a local Stack and loop while the stack is not empty.
public void DeleteDirectories(DirectoryInfo directoryInfo, bool deleteFiles)
{
Stack<DirectoryInfo> directories = new Stack<DirectoryInfo>();
directories.Push(directoryInfo);
while (directories.Count > 0)
{
var current = directories.Peek();
foreach (var d in current.GetDirectories())
directories.Push(d);
if (current != directories.Peek())
continue;
if (deleteFiles)
foreach (var f in current.GetFiles())
{
f.Delete();
}
if (current.GetFiles().Length > 0 || current.GetDirectories().Length > 0)
throw new InvalidOperationException("The directory " + current.FullName + " was not empty and could not be deleted.");
current.Delete();
directories.Pop();
}
}
I had the same problem and I created a nice (imho) solution: beggining in a root directory, I "recursively" get the children directories and I store them in an ArrayList object. In this way, I create a list contaning first the higher level dirs, and at the end the deeper nested directories. This array is ideally divided in sub-arrays using the indexes stored in the levels ArrayList object.
Doing this, I can first check the deeper directories and delete them if they're empty, and then go back to the root level by level.
For example:
private void directoryCleanup(string root)
{
try
{
// Create directory "tree"
ArrayList dirs = new ArrayList();
// Beginning and ending indexes for each level
ArrayList levels = new ArrayList();
int start = 0;
dirs.Add(root);
while (start < dirs.Count)
{
ArrayList temp = new ArrayList();
for (int i = start; i < dirs.Count; i++)
{
DirectoryInfo dinfo = new DirectoryInfo((string)dirs[i]);
DirectoryInfo[] children = dinfo.GetDirectories();
for (int j = 0; j < children.Length; j++)
{
temp.Add(children[j].FullName);
}
Array.Clear(children, 0, children.Length);
children = null;
dinfo = null;
}
start = dirs.Count;
levels.Add(dirs.Count);
dirs.AddRange(temp);
temp.Clear();
temp = null;
}
levels.Reverse();
// Navigate the directory tree level by level, starting with the deepest one
for (int i = 0; i < levels.Count - 1; i++)
{
int end = (int)levels[i] - 1;
int begin = (int)levels[i + 1];
for (int j = end; j >= begin; j--)
{
string path = (string)dirs[j];
if (Directory.GetFileSystemEntries(path).Length == 0)
{
Directory.Delete(path);
}
}
}
levels.Clear();
levels = null;
dirs.Clear();
dirs = null;
}
catch (IOException ioex)
{
// Manage exception
return;
}
catch (Exception e)
{
// Manage exception
return;
}
}
Create a queue that has all the directories in the starting directory, then while it's not empty, take the next item, check if the directory's empty, if it is delete it, if not add all the subdirectories to the queue.
I don't know C#, but if there isn't a standard queue type, a linked list or mutable array type thing would work just as well.
Pseudocode;
directories = empty queue
until directories is not empty
next = directories.shift
if next is an empty folder
delete it
or else
add all the subdiretories to the queue
Related
I have a method called clearFiles which can be called recursively if there is sub directories. I have created a counter that will count the number of files that have been deleted. The counter holds the correct number when the function is either called once or called recursively but the toast at the end of the function only returns the correct number when it is not called recursively. Is there anyway I can display the toast and then reset the number of filesCleared? Because it's just returning a 0 when it's called recursively.
From playing around with it for a bit it seems like the toast is getting called after the filesCleared variable is set to 0 which is not what I want.
filesCleared variable:
int filesCleared = 0;
clearFiles:
public async Task ClearFiles()
{
var pathName = FileFilter.PathName;
FileInfo[] files = SortFiles(pathName);
try
{
if(FileFilter.Filter == "all")
{
foreach(var file in files)
{
if(file.Extension == FileFilter.Extension || FileFilter.Extension == "all")
{
File.Delete(file.ToString());
filesCleared++;
}
}
}
if(FileFilter.Filter == "date")
{
foreach (var file in files) //regular files
{
if(file.CreationTime < FileFilter.DeleteDate) //based on time
{
if(file.Extension == FileFilter.Extension || FileFilter.Extension == "all") //based on extension
{
File.Delete(file.ToString());
filesCleared++;
}
}
}
}
if(FileFilter.Filter == "number")
{
var i = 0;
for(var j = files.Length-1; j >= 0 ; j--)
{
if(files[j].Extension == FileFilter.Extension || FileFilter.Extension == "all")
{
if(i++ >= FileFilter.FilesToKeep)
{
File.Delete(files[j].ToString());
filesCleared++;
}
}
}
}
if (FileFilter.SubFolders == true) //subfiles (will be called recursively w/ each filter)
{
foreach(var subDir in new DirectoryInfo(pathName).GetDirectories())
{
//subDir.Delete(true);
FileFilter.PathName = subDir.ToString();
ClearFiles();
//await ClearFiles(subDir.ToString());
}
FileFilter.PathName = pathName; //resets the pathName so it will go back to what it was before the recursion
}
}
catch (IOException ioExp)
{
Console.WriteLine(ioExp.Message);
Toast = Toast.Bad();
logger.LogError(ioExp, "Error Deleting");
}
Toast = Toast.Good(filesCleared + " Files Deleted");
filesCleared = 0;
}
If you want to do something once but also want to call a method recursively, you have to split it in two. After trying to simplify your code I get a ClearFiles method like this:
public void ClearFiles()
{
var filesCleared = 0;
try
{
filesCleared = DeleteFilesRecursively(FileFilter.PathName, FileFilter);
}
catch (IOException ioExp)
{
Console.WriteLine(ioExp.Message);
Toast = Toast.Bad();
logger.LogError(ioExp, "Error Deleting");
}
Toast = Toast.Good(filesCleared + " Files Deleted");
}
Now Toast.Good is only called once after all subfolders have been traversed.
Note that filesCleared is a local variable, since I don't see any point in making it global. That way you also don't need to reset it.
The implementation of DeleteFilesRecursively could be something like this and could be simplified more if you wanted:
private const string All = "all";
private const string FilterByDate = "date";
private const string FilterByNumber = "number";
int DeleteFilesRecursively(string dirPath, SomeFileFilterType fileFilter)
{
FileInfo[] files = SortFiles(dirPath);
var deleted = 0;
var toBeDeleted = files.Where(f => MatchesByExtension(f, fileFilter.Extension));
if (fileFilter.Filter == FilterByDate)
{
toBeDeleted = toBeDeleted.Where(f => MatchesByDate(f, fileFilter.DeleteDate));
}
else if (FileFilter.Filter == FilterByNumber)
{
// If your SortFiles method sorted in the other
// direction this call to Reverse would not be needed.
toBeDeleted = toBeDeleted.Reverse().Take(fileFilter.FilesToKeep);
}
foreach (var file in toBeDeleted)
{
File.Delete(file.ToString());
deleted++;
}
if (fileFilter.SubFolders)
{
foreach(var subDir in new DirectoryInfo(dirPath).GetDirectories())
{
deleted += DeleteFilesRecursively(subDir.FullName, fileFilter);
}
}
return deleted;
}
bool MatchesByExtension(FileInfo file, string extension)
=> file.Extension == extension || extension == All;
bool MatchesByDate(FileInfo file, DateTime deleteDate)
=> file.CreationTime < deleteDate;
Note that I also removed your magic strings, which could be even better by replacing them with an enum type.
I haven't tested this but I believe it should give you the same behavior as your current code (at least the parts about filtering and deleting).
I have a slightly modified codes to populate my treeView1 with only .PDF files. It works well, except it leaves with many empty folders. Is it a way to remove these folders?
private void Begin()
{
treeView1.Nodes.Clear();
if (Directory.Exists(FilePath))
LoadDirectory(FilePath);
}
public void LoadDirectory(string Dir)
{
DirectoryInfo di = new DirectoryInfo(Dir);
TreeNode tds = treeView1.Nodes.Add(di.Name);
tds.Tag = di.FullName;
tds.StateImageIndex = 0;
LoadFiles(Dir, tds);
LoadSubDirectories(Dir, tds);
}
private void LoadSubDirectories(string dir, TreeNode td)
{
// Get all subdirectories
string[] subdirectoryEntries = Directory.GetDirectories(dir);
// Loop through them to see if they have any other subdirectories
foreach (string subdirectory in subdirectoryEntries)
{
DirectoryInfo di = new DirectoryInfo(subdirectory);
TreeNode tds = td.Nodes.Add(di.Name);
tds.StateImageIndex = 0;
tds.Tag = di.FullName;
LoadFiles(subdirectory, tds);
LoadSubDirectories(subdirectory, tds);
}
}
private void LoadFiles(string dir, TreeNode td)
{
string[] Files = Directory.GetFiles(dir, "*.PDF");
// Loop through them to see files
foreach (string file in Files)
{
FileInfo fi = new FileInfo(file);
TreeNode tds = td.Nodes.Add(fi.Name);
tds.Tag = fi.FullName;
tds.StateImageIndex = 1;
}
}
I am assuming that you are being left with many empty folders in the TreeView control, and not trying to cleanup the file system. The way that I would do this would be to write a recursive method that performs this cleanup. Recursion allows us to traverse the entire tree and take action at the lowest level first, then work our way back up to the root node(s) to ensure 100% coverage with as little additional processing as possible.
This is one way to implement such a solution:
private void CleanupEmptyNodes(TreeView thisTreeView)
{
List<TreeNode> emptyChildren = new List<TreeNode>();
foreach (TreeNode topLevelNode in thisTreeView.Nodes)
{
var isEmpty = CleanupEmptyNodesRecursive(topLevelNode);
if (isEmpty)
{
emptyChildren.Add(topLevelNode);
}
}
foreach (TreeNode emptyChild in emptyChildren)
{
emptyChild.Remove();
}
}
private bool CleanupEmptyNodesRecursive(TreeNode thisTreeNode)
{
List<TreeNode> emptyChildren = new List<TreeNode>();
foreach(TreeNode node in thisTreeNode.Nodes)
{
var isEmpty = CleanupEmptyNodesRecursive(node);
if (isEmpty)
{
emptyChildren.Add(node);
}
}
//you can't delete the nodes from within the foreach
foreach(TreeNode emptyChild in emptyChildren)
{
emptyChild.Remove();
}
//were all the nodes removed?
if (thisTreeNode.Nodes.Count == 0)
{
if(/*perform test here to tell whether this node IS the file or not*/)
{
//is a file, so do not delete
return false;
}
else
{
//this is a folder, and has no contents. Delete it!
return true;
}
}
else
{
//has files within it so do not delete
return false;
}
}
Then you can just call it like this:
CleanupEmptyNodes(treeView1);
Personally, I would like it to be an extension method so I could just do treeView1.CleanupEmptyNodes(); but to each their own.
I have a problem that is doing my head in.
I want to iterate through the local PC folders, including directories, and calculate a numbering system against each folder in the file system hierarchy.
The root folders should calculate as 1,2,3 etc.
If there were three sub-folders in folder one the calculated numbers should be:
1.1, 1.2,1.3
If there were three sub-folders in the sub-folder above then the calculated numbers should be:
1.1.1, 1.1.2, 1.1.3
If there were three sub-folders in folder two (a root folder) the calculated numbers should be:
2.1, 2.2, 2.3
Or expressed in another way:
1 Root Folder
1.1 Root Sub Folder 1
1.1.1 Sub Folder
1.1.2 Sub Folder
1.2 Root Sub Folder 2
1.2.1 List item
1.2.2 List item
etc. etc.
This logic should then be applied to all folders and sub-folders.
Output Example
1.1.1 | "c:\Root\Folder1\Folder1\"
What I have so far appears to work ok in some situations but can fail in other situations:
private string rootpath = #"C:\FolderHierarchy\";
private string FolderSequenceCountBase = "";
private int CurrentRootPathCount = 0;
private int Counter = 0;
private void CalculateFolderHierarchyNumbers()
{
//Get First List of Folders
string[] Dirs = Directory.GetDirectories(rootpath, "*.*", SearchOption.TopDirectoryOnly);
for (int i = 0; i < Dirs.Count(); i++)
{
FolderSequenceCountBase = (i + 1).ToString();
CurrentRootPathCount = i + 1;
Console.WriteLine("Processed folder '{0}'.", Dirs[i] + " = " + (i + 1));
GetSubDirs(Dirs[i]);
}
}
private void GetSubDirs(string item)
{
//Get next list of folders in the folder hierarchy
string[] SubDirs = Directory.GetDirectories(item, "*.*", SearchOption.TopDirectoryOnly);
foreach (var DirPath in SubDirs)
{
//Increment count of folders within the current folder list
Counter += 1;
Console.WriteLine("Processed folder '{0}'.", DirPath + " = " + FolderSequenceCountBase + "." + Counter);
}
Counter = 0;
//Get next list of folders in the folder hierarchy
foreach (var DirPath in SubDirs)
{
FolderSequenceCountBase += ".1";
GetSubDirs(DirPath);
}
}
Hope this is clear.
Thanks
Rick
So you want to find a file and get it's the number of it in the of directory and all of it's parent directories? Since i found it interesting i've written something from scratch. Note that it's currently not tested but it might give you an idea anyway:
public static IEnumerable<FileEntryInfo> EnumerateFindFiles(string fileToFind, StringComparison comparison = StringComparison.CurrentCultureIgnoreCase, DirectoryInfo rootDir = null, string[] drivesToSearch = null)
{
IEnumerable<FileEntryInfo> foundEntries = Enumerable.Empty<FileEntryInfo>();
if (rootDir != null && drivesToSearch != null)
throw new ArgumentException("Specify either the root-dir or the drives to search, not both");
else if (rootDir != null)
{
foundEntries = EnumerateFindEntryRoot(fileToFind, rootDir, comparison);
}
else
{
if (drivesToSearch == null) // search the entire computer
drivesToSearch = System.Environment.GetLogicalDrives();
foreach (string dr in drivesToSearch)
{
System.IO.DriveInfo di = new System.IO.DriveInfo(dr);
if (!di.IsReady)
{
Console.WriteLine("The drive {0} could not be read", di.Name);
continue;
}
rootDir = di.RootDirectory;
foundEntries = foundEntries.Concat(EnumerateFindEntryRoot(fileToFind, rootDir, comparison));
}
}
foreach (FileEntryInfo entry in foundEntries)
yield return entry;
}
public class FileEntryInfo
{
public FileEntryInfo(string path, int number)
{
this.Path = path;
this.Number = number;
}
public int Number { get; set; }
public string Path { get; set; }
public FileEntryInfo Root { get; set; }
public IEnumerable<int> GetNumberTree()
{
Stack<FileEntryInfo> filo = new Stack<FileEntryInfo>();
FileEntryInfo entry = this;
while (entry.Root != null)
{
filo.Push(entry.Root);
entry = entry.Root;
}
while(filo.Count > 0)
yield return filo.Pop().Number;
yield return this.Number;
}
public override bool Equals(object obj)
{
FileEntryInfo fei = obj as FileEntryInfo;
if(obj == null) return false;
return Number == fei.Number && Path == fei.Path;
}
public override int GetHashCode()
{
return Path.GetHashCode();
}
public override string ToString()
{
return Path;
}
}
private static IEnumerable<FileEntryInfo> EnumerateFindEntryRoot(string fileNameToFind, DirectoryInfo rootDir, StringComparison comparison = StringComparison.CurrentCultureIgnoreCase)
{
Queue<FileEntryInfo> queue = new Queue<FileEntryInfo>();
FileEntryInfo root = new FileEntryInfo(rootDir.FullName, 1);
queue.Enqueue(root);
while (queue.Count > 0)
{
FileEntryInfo fe = queue.Dequeue();
List<FileEntryInfo> validFiles = new List<FileEntryInfo>();
try
{ // you cannot yield from try-catch, hence this approach
FileAttributes attr = File.GetAttributes(fe.Path);
//detect whether its a directory or file
bool isDirectory = (attr & FileAttributes.Directory) == FileAttributes.Directory;
if (isDirectory)
{
int entryCount = 0;
foreach (string entry in Directory.EnumerateFileSystemEntries(fe.Path))
{
entryCount++;
FileEntryInfo subEntry = new FileEntryInfo(entry, entryCount);
subEntry.Root = fe;
queue.Enqueue(subEntry);
attr = File.GetAttributes(entry);
isDirectory = (attr & FileAttributes.Directory) == FileAttributes.Directory;
if(!isDirectory)
validFiles.Add(subEntry);
}
}
} catch (Exception ex)
{
Console.Error.WriteLine(ex); // ignore, proceed
}
foreach (FileEntryInfo entry in validFiles)
{
string fileName = Path.GetFileName(entry.Path);
if (fileName.Equals(fileNameToFind, comparison))
yield return entry;
}
}
}
Here's how i tested it:
var allEntriesFound = EnumerateFindFiles("PresentationFramework.dll").ToList();
if(allEntriesFound.Any())
{
foreach (FileEntryInfo entry in allEntriesFound)
Console.WriteLine("{0}: Number: {1}", entry.Path, entry.Number);
// here your exact requirement:
string result = string.Join(".", allEntriesFound[0].GetNumberTree());
Console.WriteLine(result);
}
Added also a way to specify the root directory to prevent that the whole file system is searched, Usage:
var allEntriesFound = EnumerateFindFiles(
"PresentationFramework.dll",
StringComparison.CurrentCultureIgnoreCase,
new DirectoryInfo(#"C:\Windows"))
.ToList();
I'm traveling through some shares to get information/permissions .. etc
I'm using recursive to travel through all sub shares. it works fine however, the user should be able to limit the sub shares level to specific number which is a parameter in the application?
private static INodeCollection NodesLookUp(string path)
{
var shareCollectionNode = new ShareCollection(path);
// Do somethings
foreach (var directory in Directory.GetDirectories(shareCollectionNode.FullPath))
{
shareCollectionNode.AddNode(NodesLookUp(directory));
}
return shareCollectionNode;
}
this code will go all way to the lowest level, how can i stop it in specific level? for example get all shares until 2 levels only?
Thanks.
How about passing level variable and increasing it after each level of recursion call? This will allow you to control what are the current recursion level or how many levels left. Don't forget to check for null.
private const int maxDepth = 2;
private static INodeCollection NodesLookUp(string path, int level)
{
if(level >= maxDepth)
return null;
var shareCollectionNode = new ShareCollection(path);
// Do somethings
foreach (var directory in Directory.GetDirectories(shareCollectionNode.FullPath))
{
var nodes = NodesLookUp(directory, level + 1);
if(nodes != null)
shareCollectionNode.AddNode(nodes);
}
return shareCollectionNode;
}
Initial level can be zero-indexed, like
NodesLookUp("some path", 0);
Rather than using a global variable to control the level, pass the maxLevel and decrement with each recursive call.
private static INodeCollection NodesLookUp(string path, int maxLevel)
{
var shareCollectionNode = new ShareCollection(path);
if (maxLevel > 0)
{
foreach (var directory in Directory.GetDirectories(shareCollectionNode.FullPath))
{
shareCollectionNode.AddNode(NodesLookup(directory, maxLevel-1));
}
}
return shareCollectionNode;
}
What about this:
private static INodeCollection NodesLookUp(string path, Int32 currentLevel, Int32 maxLevel)
{
if (currentLevel > maxLevel)
{
return null;
}
var shareCollectionNode = new ShareCollection(path);
// Do somethings
foreach (var directory in Directory.GetDirectories(shareCollectionNode.FullPath))
{
INodeCollection foundCollection = NodesLookUp(directory, currentLevel + 1, maxLevel)
if(foundCollection != null)
{
shareCollectionNode.AddNode();
}
}
return shareCollectionNode;
}
In this case you don't have to worry about the state of your private fields being modified each time the method runs. And, as far as the rest of your code is thread-safe, it will be thread-safe.
I am learning c# and need to find a folder when the complete path is unknown. An example would be you know the the album name but not the artist in the music folder. Finding an album name is NOT the final usage for this code but the best example for this question. I am doing this with recursion and limiting the depth of the search. Everything works good except when I find the folder and list the files I want it to stop and return but it does not, it just keeps the recursion going even after I have the the folder. I have also struggled with exception handling like how to skip a folder if permissions are not valid.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace listFoldersTest
{
class Program
{
static void Main(string[] args)
{
Console.SetWindowSize(100, 50);
DirectoryInfo dir = new DirectoryInfo(#"C:\Users\username\Music");
getDirsFiles(dir, 0, 2);
Console.ReadKey();
Console.WriteLine("done");
}
public static void getDirsFiles(DirectoryInfo d, int currentDepth, int maxDepth)
{
String folderToFindName = ("albumName");
bool foundIt = false;
if (currentDepth < maxDepth)
{
DirectoryInfo[] dirs = d.GetDirectories("*.*");
foreach (DirectoryInfo dir in dirs)
{
String pathName = (dir.FullName);
Console.WriteLine("\r{0} ", dir.Name);
if (currentDepth == (maxDepth - 1))
{
if (pathName.IndexOf(folderToFindName) != -1)
{
foundIt = true;
FileInfo[] files = dir.GetFiles("*.*");
foreach (FileInfo file in files)
{
Console.WriteLine("-------------------->> {0} ", file.Name);
} //end foreach files
} // end if pathName
} // end if of get files current depth
if (foundIt == true)
{
return;
}
getDirsFiles(dir, currentDepth + 1, maxDepth);
} //end if foreach directories
} //end if directories current depth
} // end getDirsFiles function
}
}
using System;
using System.IO;
namespace listFoldersTest
{
class Program
{
private static bool foundIt;
static void Main(string[] args)
{
Console.SetWindowSize(100, 50);
try
{
DirectoryInfo dir = new DirectoryInfo(args[0]);
getDirsFiles(dir, 0, 2);
}
catch
{
}
Console.ReadKey();
Console.WriteLine("done");
}
public static void getDirsFiles(DirectoryInfo d, int currentDepth, int maxDepth)
{
if(d == null || foundIt) return;
String folderToFindName = ("albumName");
if (currentDepth < maxDepth)
{
DirectoryInfo[] dirs = d.GetDirectories("*.*");
foreach (DirectoryInfo dir in dirs)
{
String pathName = (dir.FullName);
Console.WriteLine("\r{0} ", dir.Name);
if (currentDepth == (maxDepth - 1))
{
if (pathName.IndexOf(folderToFindName) != -1)
{
foundIt = true;
FileInfo[] files = dir.GetFiles("*.*");
foreach (FileInfo file in files)
{
Console.WriteLine("-------------------->> {0} ", file.Name);
} //end foreach files
return;
} // end if pathName
} // end if of get files current depth
getDirsFiles(dir, currentDepth + 1, maxDepth);
} //end if foreach directories
} //end if directories current depth
} // end getDirsFiles function
}
}
Create a boolean at a global scope.
Default it to false.
When the folder is found, set it to true.
In your recursive function, if the value is true, return and exit from the function without doing anything.
In your case, the foundIt variable is declared and initialized within the function. Declare it at the global level, and check it first thing in the function.
For the exception handling, simply use a try/catch and exit the function if it fails.
You can use the solution from below which doesn't use a global variable.
public static string FindFolder(DirectoryInfo rootDirectory, string folderToFind, int currentDepth, int maxDepth)
{
if(currentDepth == maxDepth)
{
return null;
}
foreach(var directory in rootDirectory.GetDirectories())
{
Console.WriteLine(directory.FullName);
if(directory.Name.Equals(folderToFind,StringComparison.OrdinalIgnoreCase))
{
return directory.FullName;
}
string tempFindResult;
if((tempFindResult = FindFolder(directory,folderToFind,++currentDepth,maxDepth)) != null)
{
return tempFindResult;
}
}
return null;
}
What I think you want to do is break out of the foreach:
if (foundIt == true)
{
break; // instead of return
}
edit
...right, of course, you need to make foundIt a class member. The current scope applied to each iteration of the method.