使用递归获取目录树
递归的一个用途是导航分层数据结构,如文件系统目录树,而不知道树有多少级别或每个级别上的对象数。在此示例中,你将看到如何在目录树上使用递归来查找指定目录的所有子目录,并将整个树打印到控制台。
internal class Program
{
internal const int RootLevel = 0;
internal const char Tab = '\t';
internal static void Main()
{
Console.WriteLine("Enter the path of the root directory:");
var rootDirectorypath = Console.ReadLine();
Console.WriteLine(
$"Getting directory tree of '{rootDirectorypath}'");
PrintDirectoryTree(rootDirectorypath);
Console.WriteLine("Press 'Enter' to quit...");
Console.ReadLine();
}
internal static void PrintDirectoryTree(string rootDirectoryPath)
{
try
{
if (!Directory.Exists(rootDirectoryPath))
{
throw new DirectoryNotFoundException(
$"Directory '{rootDirectoryPath}' not found.");
}
var rootDirectory = new DirectoryInfo(rootDirectoryPath);
PrintDirectoryTree(rootDirectory, RootLevel);
}
catch (DirectoryNotFoundException e)
{
Console.WriteLine(e.Message);
}
}
private static void PrintDirectoryTree(
DirectoryInfo directory, int currentLevel)
{
var indentation = string.Empty;
for (var i = RootLevel; i < currentLevel; i++)
{
indentation += Tab;
}
Console.WriteLine($"{indentation}-{directory.Name}");
var nextLevel = currentLevel + 1;
try
{
foreach (var subDirectory in directory.GetDirectories())
{
PrintDirectoryTree(subDirectory, nextLevel);
}
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine($"{indentation}-{e.Message}");
}
}
}
此代码比完成此任务的最低限度更复杂,因为它包括异常检查以处理获取目录的任何问题。你可以在下面找到将代码拆分为较小的段,并对每个段进行说明。
Main
:
main 方法将来自用户的输入作为字符串,该字符串用作根目录的路径。然后使用此字符串作为参数调用 PrintDirectoryTree
方法。
PrintDirectoryTree(string)
:
这是处理实际目录树打印的两种方法中的第一种。此方法将表示根目录路径的字符串作为参数。它检查路径是否是实际目录,如果不是,则抛出 DirectoryNotFoundException
,然后在 catch 块中处理。如果路径是真实目录,则从路径创建 DirectoryInfo
对象 rootDirectory
,并使用 rootDirectory
对象和 RootLevel
调用第二个 PrintDirectoryTree
方法,RootLevel
是一个值为零的整数常量。
PrintDirectoryTree(DirectoryInfo, int)
:
第二种方法处理工作的主要问题。它需要一个 DirectoryInfo
和一个整数作为参数。DirectoryInfo
是当前目录,整数是目录相对于根的深度。为了便于阅读,输出将缩进当前目录的每个级别,以便输出如下所示:
-Root
-Child 1
-Child 2
-Grandchild 2.1
-Child 3
打印当前目录后,将检索其子目录,然后在每个目录上调用此方法,其深度级别值比当前值大 1。那部分是递归:调用自身的方法。程序将以这种方式运行,直到它访问了树中的每个目录。当它到达没有子目录的目录时,该方法将自动返回。
此方法还捕获 UnauthorizedAccessException
,如果当前目录的任何子目录受系统保护,则抛出 UnauthorizedAccessException
。为了一致性,将在当前缩进级别打印错误消息。
下面的方法提供了解决此问题的更基本方法:
internal static void PrintDirectoryTree(string directoryName)
{
try
{
if (!Directory.Exists(directoryName)) return;
Console.WriteLine(directoryName);
foreach (var d in Directory.GetDirectories(directoryName))
{
PrintDirectoryTree(d);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
这不包括第一种方法的特定错误检查或输出格式,但它实际上做了同样的事情。由于它只使用字符串而不是 DirectoryInfo
,因此无法访问其他目录属性(如权限)。