形成文件和文件夹树

Form a tree of files and folders

如何递归地从文件夹中获取所有文件夹和文件树?我需要将这棵树放入 DataTable 并从中形成一个 treeView。我在形成递归方法时遇到了一点问题,目前我只有一个不能正常工作的草稿:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SWPF
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private int id, parentID;
        private List<TREE> tree;
        public MainWindow()
        {
            InitializeComponent();

            tree = new List<TREE>();
            id = 0;
            parentID = 0;

            fill(@"D:\c#");
        }

        private List<TREE> fill(string path)
        {
            DirectoryInfo dir = new DirectoryInfo(path);
            foreach (DirectoryInfo folder in dir.GetDirectories())
            {
                tree.Add(new TREE(){ID = id++, ParentID = parentID++, Name = folder.Name, Type = "Folder"});

                foreach (FileInfo file in folder.GetFiles())
                {
                    tree.Add(new TREE() { ID = id, ParentID = parentID, Name = file.Name, Type = "File" });  
                }
                var p = folder.GetDirectories();
                if (p.Length > 0)
                {
                    dir = folder;
                    fill(dir.FullName);
                }
            }
            return tree;
        }
    }

public class TREE
{
    public int ID { get; set; }
    public int ParentID {get;set;}
    public string Name {get;set;}
    public string Type {get;set;}
}

}

拜托,你能告诉我形成树并将树放入 DataTable 的正确方法吗?列表很好,但我需要数据表。

我试过了,但它不能正常工作:

public DataTable fill(DirectoryInfo dir)
        {
            DataTable dt = new DataTable("Tasks");

            //dt.Columns.Add("ID");
            dt.Columns.Add("ParentID");
            dt.Columns.Add("Name");
            dt.Columns.Add("Type");

            foreach (var folder in dir.GetDirectories())
            {
                var row = dt.NewRow();

                row["ParentID"] = folder.Parent;
                row["Name"] = folder.Name;
                row["Type"] = "dir";
                dt.Rows.Add(row);

                foreach (var file in folder.GetFiles())
                {
                    var row2 = dt.NewRow();

                    row["ParentID"] = folder.Parent;
                    row["Name"] = file.Name;
                    row["Type"] = "file";
                    dt.Rows.Add(row2);
                }

                fill(folder);
            }
            return dt;
        }

下面是我如何实现递归部分:

static class IdGenerator
{
    static int _id = 1;
    public static int Generate() { return _id++; }
}

class Tree
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int ParentId { get; set; }
    public Tree Parent { get; set; }
    public virtual ICollection<string> Files { get; set; }
    public virtual ICollection<Tree> Trees { get; set; }

    internal Tree ()
    {
        Id = IdGenerator.Generate();
        Name = String.Empty;
        ParentId = 0;
        Parent = null;
        Files = new List<string>();
        Trees = new List<Tree>();
    }

    public override string ToString()
    {
        return String.Join("\n", new[] { Id + "\t" + Path.Combine(Parent != null ? Parent.Name : String.Empty, Name) }.Union(Files).Union(Trees.Select(t => t.ToString()))) + "\n";
    }

    public static Tree CreateTree(string path, Tree parent, string pattern)
    {
        try
        {
            var tree = new Tree
            {
                Parent = parent,
                ParentId = parent != null ? parent.Id : 0,
                Name = Path.GetFileName(path),
                Files = Directory.GetFiles(path, pattern, SearchOption.TopDirectoryOnly).Select(f => Path.GetFileName(f)).ToArray(),
            };
            tree.Trees = Directory.GetDirectories(path, "*.*", SearchOption.TopDirectoryOnly).Select(d => CreateTree(d, tree, pattern)).ToArray();

            return tree;
        }
        catch (UnauthorizedAccessException)
        { return new Tree(); }
    }
}

如果我要继续这样做,我会使用 Entity Framework Code First 从 POCO Tree 生成数据库,并删除静态 IdGenerator 因为 EF 会生成这些数据库我的 ID。

编辑

但是,以下是在 DataTable 中执行此操作的方法:

class TreeDataTable : DataTable
{
    public TreeDataTable()
        : this("trees")
    {
    }

    public TreeDataTable(string tableName)
        : base(tableName)
    {
        Columns.Add("Id");
        Columns.Add("Name");
        Columns.Add("ParentId");
        Columns.Add("Type");
    }

    public void AddFile(int id, string name, int parent)
    {
        AddRow(id, name, parent, typeof(FileInfo));
    }

    public void AddTree(Tree tree)
    {
        AddRow(tree.Id, tree.Name, tree.ParentId, typeof(DirectoryInfo));
        var table = tree.ToDataTable();
        foreach (var r in table.Rows.Cast<DataRow>())
            AddRow(Convert.ToInt32(r["Id"]), r["Name"].ToString(), Convert.ToInt32(r["ParentId"]), Type.GetType(r["Type"].ToString()));
    }

    public string ToXml()
    {
        using (var sw = new StringWriter())
        {
            using (var tw = new XmlTextWriter(sw))
            {
                tw.Formatting = Formatting.Indented;

                tw.WriteStartDocument();
                tw.WriteStartElement(TableName);

                ((IXmlSerializable)this).WriteXml(tw);

                tw.WriteEndElement();
                tw.WriteEndDocument();

            }

            return sw.ToString();
        }
    }

    private void AddRow(int id, string name, int parent, Type type)
    {
        var row = NewRow();
        row["Id"] = id;
        row["Name"] = name;
        row["ParentId"] = parent;
        row["Type"] = type.ToString();

        Rows.Add(row);
    }
}

并将此方法添加到 Tree:

    public DataTable ToDataTable()
    {
        var table = new TreeDataTable();

        foreach (var f in Files)
            table.AddFile(IdGenerator.Generate(), f, Id);
        foreach (var t in Trees)
            table.AddTree(t);

        return table;
    }

使用方法如下:

class Program
{
    static void Main(string[] args)
    {
        var path = args.FirstOrDefault(a => !String.IsNullOrEmpty(a)) ?? @"C:\Documents\Videos";
        args = args.Skip(1).ToArray();
        var pattern = args.FirstOrDefault(a => !String.IsNullOrEmpty(a)) ?? "*.mp4";
        var tree = Tree.CreateTree(path, null, pattern);

        Console.WriteLine((tree.ToDataTable() as TreeDataTable).ToXml());
    }
}