Click here to Skip to main content
15,867,990 members
Articles / Programming Languages / C#
Tip/Trick

DirTree: A Simplified Directory Tree Tool

Rate me:
Please Sign up or sign in to vote.
3.90/5 (6 votes)
29 Jun 2022CPOL 8.3K   158   11   13
Console app to scan a VS directory and create a simplified directory tree
This is a quick and dirty Console app written in VS2019 and .NET 4.8 to scan a VS directory and create a simplified directory tree.

Introduction

This quick and dirty Console app can be used to produce a simplified tree representation similar to the DOS Tree command, but with an option to limited the tree depth.

Directories starting with '.' are excluded, and also other directories like bin and obj.

Below is an example tree from the open-source Budoco VS Code solution (Bug Tracker in ASP.NET Core available on GitHub).

Image 1

Using the Code

Command line usage:

DirTree [path] [depth]

If no path is given, the current directory is used.
Depth must be >= 0, default value is 2.

So without further ado, here is the source code:

C#
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;

namespace DirTree
{
    /// <summary>
    /// Console app to scan a VS directory and create a simplified directory tree.
    /// Command line usage: 
    ///   DirTree [path] [depth]
    /// If no path is given, the current directory is used.
    /// Depth must be >= 0, default value is 2.
    /// </summary>
    class Program
    {
        static string filter = "*.*";
        static string startPath;
        static List<string> excludeList = new List<string>();
        static int folderLevel;
        static int treeDepth = 2;
        static int folderLevelStart;
        static string lastFolder;
        static bool lastDirFlag;
        static int tabSize = 3;
        static StringBuilder sbTree;        // Optionally write to DirTree.txt

        static void Main(string[] args)
        {
            if (args.Length > 0)
            {
                startPath = args[0];

                if (args.Length > 1)
                {
                    treeDepth = int.Parse(args[1]);
                }
            }

            if (string.IsNullOrEmpty(startPath))
            {
                startPath = Environment.CurrentDirectory;
            }

            if (!startPath.EndsWith(@"\"))
            {
                startPath += @"\";
            }

            sbTree = new StringBuilder(50);
            sbTree.AppendLine(startPath);
            sbTree.AppendLine();

            // Add directories to exclude
            excludeList.Add("bin");
            excludeList.Add("obj");
            excludeList.Add("x64");
            excludeList.Add("x86");
            excludeList.Add("Properties");

            folderLevelStart = startPath.Count(x => x == '\\');
            var dirs = GetFoldersFiltered(startPath, filter);

            if (dirs.Length > 0)
            {
                lastFolder = dirs[dirs.Length - 1];
                ScanFolders(startPath);
                //File.WriteAllText("DirTree.txt", sbTree.ToString()); // Enable this 
                                                          // to write DirTree.txt
            }
            else
            {
                Console.WriteLine("No directories found.");
            }

            Console.ReadKey();
        }

        /// <summary>
        /// Get folders array, exclude folders with excludeList and 
        /// starting with '.' like .git .vs.
        /// </summary>
        /// <param name="path">The path</param>
        /// <param name="filter">Wildcard filter</param>
        /// <returns>A string array</returns>
        static string[] GetFoldersFiltered(string path, string filter)
        {
            var folders = Directory.GetDirectories(path, filter).ToList();

            for (int i = folders.Count - 1; i >= 0; i--)
            {
                string dirFullname = folders[i];
                string dirname = dirFullname.Replace(path, "");

                if (dirname.StartsWith(".") || excludeList.Contains(dirname))
                {
                    folders.RemoveAt(i);
                }
            }

            return folders.ToArray();
        }

        /// <summary>
        /// Recursively scan folders with a depth of <see cref="treeDepth"/>.
        /// </summary>
        /// <param name="path">The start path</param>
        /// <param name="continueLine">The folder level to continue vertical line
        /// </param>
        /// <param name="previous_indent">The previous indentation</param>
        static void ScanFolders(string path, int continueLine = -1, 
                                string previous_indent = "")
        {
            int i = 0;

            if (!path.EndsWith(@"\"))
            {
                path += @"\";
            }

            var dirs = GetFoldersFiltered(path, filter);
            int lastNode = dirs.Length - 1;

            while (i < dirs.Length)
            {
                string dirFullname = dirs[i];
                string dirname = dirFullname.Replace(path, "");
                string indent = "  ";
                string indent2 = string.Empty;

                if (dirFullname.StartsWith(lastFolder))
                {
                    lastDirFlag = true;
                }

                folderLevel = dirFullname.Count(x => x == '\\') - folderLevelStart;

                for (int j = 0; j < folderLevel; j++)
                {
                    if (lastDirFlag && continueLine >= j)
                    {
                        indent += " " + new string(' ', tabSize);
                    }
                    else
                    {
                        indent += "│" + new string(' ', tabSize);
                    }
                }

                if (previous_indent.Length > 0)
                {
                    indent = previous_indent + indent.Substring(previous_indent.Length);
                }

                if (i == lastNode)
                {
                    indent2 = "└" + new string('─', tabSize);
                    continueLine = folderLevel;
                }
                else
                {
                    indent2 = "├" + new string('─', tabSize);
                }

                Console.WriteLine($"{indent}{indent2}{dirname}");
                sbTree.AppendLine($"{indent}{indent2}{dirname}");

                if (folderLevel < treeDepth)
                {
                    if (i == lastNode)
                    {
                        indent += " " + new string(' ', tabSize);
                    }

                    // Recursive call
                    ScanFolders(dirFullname, continueLine, indent);
                }

                i++;
            }
        }
    }
}

History

  • 29th June, 2022: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Netherlands Netherlands
Software developer in the Netherlands, currently working on Video Surveillance applications.
Experience: C#, C++, VB, ASP, SQL Server, PostgreSQL, Gitea, TeamCity.
It all started with Black&White, no not the whiskey but the Sinclair ZX81 followed by several Atari's and PC's. The journey continues ...

Comments and Discussions

 
QuestionPowerShell Conversion Pin
Brooks Vaughn (US)2-Jul-22 7:36
Brooks Vaughn (US)2-Jul-22 7:36 
PraiseRe: PowerShell Conversion Pin
RickZeeland2-Jul-22 8:00
mveRickZeeland2-Jul-22 8:00 
GeneralRe: PowerShell Conversion Pin
Brooks Vaughn (US)3-Jul-22 4:52
Brooks Vaughn (US)3-Jul-22 4:52 
GeneralRe: PowerShell Conversion Pin
Andreas Saurwein4-Jul-22 1:07
Andreas Saurwein4-Jul-22 1:07 
QuestionDeferred Execution Pin
George Swan30-Jun-22 9:29
mveGeorge Swan30-Jun-22 9:29 
AnswerRe: Deferred Execution Pin
RickZeeland30-Jun-22 9:36
mveRickZeeland30-Jun-22 9:36 
GeneralRe: Deferred Execution Pin
George Swan30-Jun-22 9:46
mveGeorge Swan30-Jun-22 9:46 
GeneralRe: Deferred Execution Pin
RickZeeland30-Jun-22 21:00
mveRickZeeland30-Jun-22 21:00 
QuestionOutput Example? Pin
DSchopp29-Jun-22 6:56
professionalDSchopp29-Jun-22 6:56 
PraiseRe: Output Example? Pin
RickZeeland29-Jun-22 7:29
mveRickZeeland29-Jun-22 7:29 
QuestionDownload Pin
George Swan29-Jun-22 3:06
mveGeorge Swan29-Jun-22 3:06 
Rick, Thanks for the useful piece. Is the download link functional? It simply redirects my browser to this page.

AnswerRe: Download Pin
RickZeeland29-Jun-22 3:29
mveRickZeeland29-Jun-22 3:29 
GeneralRe: Download Pin
George Swan29-Jun-22 6:10
mveGeorge Swan29-Jun-22 6:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.