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