0

I was just wondering, if there is a quick solution for getting the level of the deepest folder in my root Directory.

Lets say I work with "C:\" then I need a function which gets me the number of levels there are to the "deepest" folder in root directory without iterating over each directory.

Felix D.
  • 4,811
  • 8
  • 38
  • 72
  • How would you know the deepest level of any folder in your root drive if you don't want to iterate through it. (by yourself or any provided function in System.IO)? – grmbl Mar 04 '16 at 11:54
  • The question is if there is a Function which gets it for me. I need to know the count. – Felix D. Mar 04 '16 at 11:55

2 Answers2

1

Your best bet is to use System.IO.DirectoryInfo GetDirectories recursively. Be sure NOT to use SearchOption.AllDirectories because that will surely break with a security error!

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();

    }

But you will run against a PathTooLongException, take a look at this question how to solve this.

Community
  • 1
  • 1
grmbl
  • 2,514
  • 4
  • 29
  • 54
  • But this will only get me all the SubDirs of C:\ or am I wrong ? – Felix D. Mar 04 '16 at 12:08
  • Hold on, I'll make you an example. – grmbl Mar 04 '16 at 12:11
  • This is my longest (string) ;,,; C:\Users\OOO\.atom\packages\atom-yeoman\node_modules\tsd\node_modules\update-notifier\node_modules\latest-version\node_modules\package-json\node_modules\got\node_modules\duplexify\node_modules\end-of-stream\node_modules\once\node_modules\wrappy\test – grmbl Mar 04 '16 at 12:34
  • KK nice imma try this out thanks alot for your effort – Felix D. Mar 04 '16 at 12:34
  • Nice job that Recursive call is doing a great job. still taking a while :P – Felix D. Mar 04 '16 at 12:36
  • Yeah, you should run this kind of things on another thread or buy a faster pc.. :) – grmbl Mar 04 '16 at 12:39
  • Yeah its my pc at work ^^ my homemachine has an ssd ^^ was just wondering if its possible at all :D anyways thanks alot for your help – Felix D. Mar 04 '16 at 15:14
0

I was bothered by the PathTooLongException and came up with this:

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);
        }
    }
}

Use as var directories = DirectoryEx.GetDirectories("C:\\");

This will create a virtual drive (using SUBST) for each path that is too long so it can still iterate through it. Needs optimization and could be extended to provide some DirectoryInfo wrapper class.

grmbl
  • 2,514
  • 4
  • 29
  • 54