Home > Blockchain >  Get the hierarchy (Parent-Child) of a directory with folders and files
Get the hierarchy (Parent-Child) of a directory with folders and files

Time:11-04

How to get a Parent-Child relationship or Tree from a directory with folders and files.

Given the following directory:

Root  
└───folder1
│   │   file011.txt
│   │   file012.txt
│   │
│   └───subfolder1
│       │   file111.txt
│       │   file112.txt
│       │   ...
│   
└───folder2
    │   file021.txt
    │   file022.txt

Item holds the information, it can be a folder or a file.

public class Item
{
        public string Name { get; set; }
        public IEnumerable<Item> Children { get; set; } = new List<Item>();
        public bool isDirectory{ get; set; }
}

I basically want a function which returns me the desired result in parent-child list.

var mainDirectory = new DirectoryInfo(@"D:\RootFolder");

var result = getTreeList(mainDirectory) <-- returns IEnumerable<Item>

perhaps LINQ could come in handy??

I tried fiddling around with EnumerateFileSystemInfos and GetFileSystemEntries but they give me back a flat structure of the directory.

CodePudding user response:

You could try using something like the below recursive method:

    private static List<Item> GetFilesFromDirectories(IEnumerable<string> directories)
    {
        List<Item> treeItems = new List<Item>();
        foreach (string directory in directories)
        {
            string[] folders = Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly);
            List<Item> subFolderItems = GetFilesFromDirectories(folders);

            string[] files = Directory.GetFiles(directory, $"*.*", SearchOption.TopDirectoryOnly);
            foreach (string file in files)
            {
                Item fileItem = new Item
                {
                    Name = Path.GetFileName(file),
                };

                subFolderItems.Add(fileItem);
            }

            string folderName = new DirectoryInfo(directory).Name;
            Item directoryItem = new Item
            {
                Name = folderName,
                Children = subFolderItems,
                IsDirectory = true
            };
            treeItems.Add(directoryItem);
        }

        return treeItems;
    }

If you want to call and display this in a console app (for example), you could use it as per the below:

    static void Main(string[] args)
    {
        var items = GetFilesFromDirectories(new[] { @"C:\foo" });

        DisplayTree(items);

        Console.ReadLine();
    }

    private static void DisplayTree(List<Item> items, int depth = 1)
    {
        string branch = new string('-', depth);
        foreach (var item in items)
        {
            if (item.Children.Any())
            {
                int newDepth = depth   1;
                Console.WriteLine($"| {branch} [{item.Name}]");
                DisplayTree(item.Children.ToList(), newDepth);
            }
            else
            {
                Console.WriteLine($"| -{branch} {item.Name}");
            }
        }
    }

CodePudding user response:

You can read the directory and files recursively, and pass the parent Item along in the method, like so:

Item ReadFilesAndDirectories(string path)
{
    void ReadFilesAndDirectoriesRecursive(string path, Item parent)
    {
        foreach (var directory in Directory.GetDirectories(path))
        {
            var childDirectoryItem = new Item
            {
                Name = Path.GetDirectoryName(directory),
                IsDirectory = true 
            };

            parent.Children.Add(childDirectoryItem);

            ReadFilesAndDirectoriesRecursive(
                Path.Combine(path, directory), childDirectoryItem);

            foreach (var file in Directory.GetFiles(path))
            {
                var childFileItem = new Item
                {
                    Name = Path.GetFileName(file)
                };

                parent.Children.Add(childFileItem);
            }
        }
    }

    var root = new Item { Name = path, IsDirectory = true };
    ReadFilesAndDirectoriesRecursive(path, root);
    return root;
}

I have wrapped it in another method that takes care of the initialization of the root directory.

You can then print the directory structure and the files in the following way:

void PrintItems(Item item, int depth = 0)
{
    foreach (var child in item.Children)
    {
        Console.WriteLine("".PadLeft(depth * 2, ' ' ) 
            $"{child.Name} (Directory: {child.IsDirectory})");

        PrintItems(child, depth   1);
    }
}

You can use this like so:

var items = ReadFilesAndDirectories(@"C:/PickAFolder...");
PrintItems(items);
  • Related