获取最大目录深度

Get maximum directorydepth

我只是想知道,是否有快速解决方案来获取我的根目录中最深文件夹的级别。

假设我使用 "C:\",那么我需要一个函数来获取根目录中 "deepest" 文件夹的级别数,而无需遍历每个目录。

最好的办法是递归地使用 System.IO.DirectoryInfo GetDirectories。一定不要使用 SearchOption.AllDirectories 因为那样会 肯定会因安全错误而中断!

static List<string> directories = new List<string>();
        static void GetDirectories(string path)
        {
            try
            {
                foreach (var directory in Directory.GetDirectories(path))
                {
                    var di = new DirectoryInfo(directory);
                    directories.Add(di.FullName);
                    GetDirectories(di.FullName);
                }
            }
            catch (UnauthorizedAccessException uaex) { }
            catch (PathTooLongException ptlex) { }
            catch (Exception ex) { }
        }

static void Main(string[] args)
    {
        var path = @"C:\";

        GetDirectories(path);

        var maxLevel = directories.Max(d => d.Split('\').Count());
        var deepest = directories.Select(d => new
            {
                Path = d,
                Levels = d.Split('\').Count()
            })
        .OrderByDescending(d => d.Levels)
        .First();

    }

但是你会运行反对PathTooLongException,看看this question如何解决这个问题。

我被 PathTooLongException 困扰并想出了这个:

public static class DirectoryEx
{
    static char driveLetter;
    static string longPath;
    static List<string> directories;

    static DirectoryEx()
    {
        longPath = String.Empty;
    }

    private static char GetAvailableDrive()
    {
        var all = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray().Reverse();
        var occupied = DriveInfo.GetDrives()
            .OrderByDescending(d => d.Name)
            .Select(d => (char)d.Name.ToUpper().First());

        var free = all.Except(occupied).First();

        return free;
    }

    public static List<string> GetDirectories(string path)
    {
        directories = new List<string>();

        // recursive call
        FindDirectories(path);

        return directories;
    }

    static void FindDirectories(string path)
    {
        try
        {
            foreach (var directory in Directory.GetDirectories(path))
            {
                var di = new DirectoryInfo(directory);

                if(!String.IsNullOrEmpty(longPath))
                    directories.Add(di.FullName.Replace(driveLetter + ":\", longPath + "\"));
                else
                    directories.Add(di.FullName);

                FindDirectories(di.FullName);
            }
        }
        catch (UnauthorizedAccessException uaex) { Debug.WriteLine(uaex.Message); }
        catch (PathTooLongException ptlex)
        {
            Debug.WriteLine(ptlex.Message);

            longPath = path;

            Task t = new Task(new Action(() =>
            {
                CreateVirtualDrive(longPath);
                FindDirectories(driveLetter + ":\");
                DeleteVirtualDrive();

                longPath = String.Empty;
            }));

            if (!String.IsNullOrEmpty(longPath))
                t.RunSynchronously();
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message); 
        }
    }

    static void CreateVirtualDrive(string path)
    {
        driveLetter = GetAvailableDrive();

        Process.Start(new ProcessStartInfo() {
            FileName = "cmd.exe",
            WindowStyle = ProcessWindowStyle.Hidden,
            Arguments = String.Format("/c subst {0}: {1}", driveLetter.ToString(), path)
        });

        while (!DriveInfo.GetDrives().Select(d => d.Name.ToUpper().First()).Contains(driveLetter))
        {
            System.Threading.Thread.Sleep(1);
        }
    }

    static void DeleteVirtualDrive()
    {
        Process.Start(new ProcessStartInfo()
        {
            FileName = "cmd.exe",
            WindowStyle = ProcessWindowStyle.Hidden,
            Arguments = String.Format("/c subst {0}: /D", driveLetter.ToString())
        });

        while (DriveInfo.GetDrives().Select(d => d.Name.ToUpper().First()).Contains(driveLetter))
        {
            System.Threading.Thread.Sleep(1);
        }
    }
}

用作var directories = DirectoryEx.GetDirectories("C:\");

这将为每个太长的路径创建一个虚拟驱动器(使用 SUBST),因此它仍然可以遍历它。需要优化,可以扩展以提供一些 DirectoryInfo 包装器 class.