Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I convert a list of filenames to a tree structure?

Tags:

c#

tree

I have a string array of some file paths:

path/to/folder/file.xxx
path/to/other/
path/to/file/file.xx
path/file.x
path/

How can I convert this list to a tree structure? So far I have the following:

/// <summary>
/// Enumerates types of filesystem nodes.
/// </summary>
public enum FilesystemNodeType
{
    /// <summary>
    /// Indicates that the node is a file.
    /// </summary>
    File,

    /// <summary>
    /// Indicates that the node is a folder.
    /// </summary>
    Folder
}

/// <summary>
/// Represents a file or folder node.
/// </summary>
public class FilesystemNode
{
    private readonly ICollection<FilesystemNode> _children; 

    /// <summary>
    /// Initializes a new instance of the <see cref="FilesystemNode"/> class.
    /// </summary>
    public FilesystemNode()
    {
        _children = new LinkedList<FilesystemNode>();
    }

    /// <summary>
    /// Gets or sets the name of the file or folder.
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// Gets or sets the full path to the file or folder from the root.
    /// </summary>
    public string Path { get; set; }

    /// <summary>
    /// Gets or sets a value indicating whether the node is a file or folder.
    /// </summary>
    public FilesystemNodeType Type { get; set; }

    /// <summary>
    /// Gets a list of child nodes of this node. The node type must be a folder to have children.
    /// </summary>
    public ICollection<FilesystemNode> Children
    {
        get
        {
            if (Type == FilesystemNodeType.Folder)
                return _children;

            throw new InvalidOperationException("File nodes cannot have children");
        }
    }
}

I'm just a bit at a loss at how to actually split up the paths and all. Any path that ends with a / is a directory, any one that doesn't, is not.

Also, while my input will always contain a path to the folder, how would I account for that situation if it did not?

For example, if I had the input:

path/to/file.c
path/file.c
path/

How would I account for the fact that path/to/ is not in the input?

like image 498
Jake Petroules Avatar asked Dec 23 '11 23:12

Jake Petroules


People also ask

What is a tree structure of folders?

Tree-structured directoryThe directory is structured in the form of a tree. It also has a root directory, and every file in the system has a unique path. A directory within a tree-structured directory may contain files or subdirectories. Special system calls are used to create or remove directories.

What is a tree structure file?

A tree data structure is an algorithm for placing and locating files (called records or keys) in a database. The algorithm finds data by repeatedly making choices at decision points called nodes. A node can have as few as two branches (also called children) or as many as several dozen.


1 Answers

Here is a solution that generates a nested dictionary of NodeEntry items (you can substitute your file info class as needed):

public class NodeEntry
{
    public NodeEntry()
    {
        this.Children = new NodeEntryCollection();
    }

    public string Key { get; set; }
    public NodeEntryCollection Children { get; set; }

}

public class NodeEntryCollection : Dictionary<string, NodeEntry>
{
    public void AddEntry(string sEntry, int wBegIndex)
    {
        if (wBegIndex < sEntry.Length)
        {
            string sKey;
            int wEndIndex;

            wEndIndex = sEntry.IndexOf("/", wBegIndex);
            if (wEndIndex == -1)
            {
                wEndIndex = sEntry.Length;
            }
            sKey = sEntry.Substring(wBegIndex, wEndIndex - wBegIndex);
            if (!string.IsNullOrEmpty(sKey)) {
                NodeEntry oItem;

                if (this.ContainsKey(sKey)) {
                    oItem = this[sKey];
                } else {
                    oItem = new NodeEntry();
                    oItem.Key = sKey;
                    this.Add(sKey, oItem);
                }
                // Now add the rest to the new item's children
                oItem.Children.AddEntry(sEntry, wEndIndex + 1);
            }
        }
    }
}

To use the above, create a new collection:

        NodeEntryCollection cItems = new NodeEntryCollection();

then, for each line in your list:

        cItems.AddEntry(sLine, 0);
like image 91
competent_tech Avatar answered Nov 09 '22 20:11

competent_tech