问题
I wrote this code to recursively list files and folders in c#.
var filesInTheCurrentDirectory = System.IO.Directory.GetFiles(rootFolder);
if (!filesInTheCurrentDirectory.Any() && !System.IO.Directory.GetDirectories(rootFolder).ToList().Any())
{
return;
}
filesInTheCurrentDirectory.ToList().ForEach(file => System.IO.File.AppendAllText("e:\\personal\\tests.txt", System.IO.Path.GetFileName(file) + ":" + rootFolder + "\n"));
System.IO.Directory.GetDirectories(rootFolder).ToList().ForEach(recursivePrintFolders);
While this just works great, the question is:
I am using recursion. Is this way the
best? (I tried writing a non-recursive function but stuck up because we do not know what is the depth of each folder in advance).How to evaluate the performance of this function ? Is it
OlogNorO(n)? (I am confused because there is no looping version. According to me, if there is twoforloops, i can just call itO(n^2).)
Any ideas or guidance's ?
回答1:
The main problems with using recursion to do this is:
If your tree has a depth that is too large you may not have enough stack space. While it would be uncommon to have that deep of a file system structure, it's not inconceivable.
You are using more memory than needed, in that you're holding onto a lot of data in stack frames that you could potentially avoid.
As for the asymptotic complexity, you're performing one operation per node, regardless of it's size, so it's O(n), where n is all nodes, not the nodes at any given depth.
However, you can handle all of this much more effectively using the built in method to traverse the entire tree. It is going to be more efficient than a solution you'll come up with, even if yours is non-recursive, just use:
foreach(string file in Directory.EnumerateFiles(path, "*",
SearchOption.AllDirectories))
{
System.IO.File.AppendAllText("e:\\personal\\tests.txt",
System.IO.Path.GetFileName(file) + ":" + rootFolder + "\n")
}
While that solution is likely not to use recursion, if you want to know how to write a non-recursive tree traversal yourself, you can use a general purpose method like this:
public static IEnumerable<T> Traverse<T>(
this IEnumerable<T> source
, Func<T, IEnumerable<T>> childrenSelector)
{
var stack = new Stack<T>(source);
while (stack.Any())
{
var next = stack.Pop();
yield return next;
foreach (var child in childrenSelector(next))
stack.Push(child);
}
}
In your case calling it could look something like this:
var allFiles = new[] { new DirectoryInfo(path) }
.Traverse(directory => directory.EnumerateDirectories())
.Select(directory => directory.EnumerateFiles());
Note that, while this is fine for traversing a tree that doesn't provide a built in way for a full traversal, this is generally not ideal for traversing the file system. You should use the first solution in that it has been highly optimized already for the special case of traversing a file system.
来源:https://stackoverflow.com/questions/20196395/recursively-listing-of-files-and-folders-in-c-sharp