Dot.Blog

C#, XAML, WinUI, WPF, Android, MAUI, IoT, IA, ChatGPT, Prompt Engineering

Créer un arbre des répertoires avec XML (et l'interroger avec LINQ to XML)

Pour les besoins d'un prochain billet je voulais obtenir une structure arborescente de test sous la forme d'un fichier XML. Une telle chose peut se faire à la main mais cela est fastidieux et à force de copier/coller les données seront trop semblables et donc peu utilisables pour des tests et du debug, ce qui est dommage puisque tel était le but recherché...

Pour générer des données aléatoires mais réalistes je possède déjà un outil fantastique (puisque c'est moi qui l'est fait :-) ), DataGen, un logiciel puissant mais qui n'est pas étudié pour générer des données dont la strucuture est récursive. Restait donc à concevoir un utilitaire pour satisfaire mon besoin de l'instant.

Je n'aime pas développer "pour rien" donc il fallait que cet utilitaire en soit bien un. Tout disque dur de développeur contient une telle quantité de données que l'ensemble des répertoires forment une superbe structure arborescente ni trop petite ni trop gigantesque. Exactement ce qu'il faut pour des tests ! Ainsi, l'outil devra fabriquer un fichier XML à partir de n'importe quel niveau de répertoire, la structure étant hiérarchique.

Je m'empresse donc de vous faire partager ce petit bout de code qui vous sera utile un jour ou l'autre je pense.

using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
 
namespace Enaxos.Tools.Xml
{
    /// <summary>
    /// This class can generate an XML file from a folder hierarchy.
    /// </summary>
    public static class DirToXml
    {
        /// <summary>
        /// Builds the tree document.
        /// </summary>
        /// <param name="dirname">The name of the starting folder.</param>
        /// <returns>a LINQ to XML <c>XDocument</c></returns>
        public static XDocument BuildTreeDocument(string dirname)
        {
            return new XDocument(new XDeclaration("1.0", "utf-8", "yes"), 
                new XComment("Structure au "+DateTime.Now),new XElement("directories", BuildTree(dirname)));
        }
 
        /// <summary>
        /// Builds the tree (recursive method).
        /// </summary>
        /// <param name="dirName">Name of the starting folder.</param>
        /// <returns>a LINQ to XML <c>XElement</c> being the root (or 1st item) of the tree.</returns>
        public static XElement BuildTree(string dirName)
        {
            var di = new DirectoryInfo(dirName);
            var files = di.GetFiles();
            var dirsize = 0l;
            foreach (var file in files)
            {
                dirsize += file.Length;
            }
            var subdirs = di.GetDirectories();
            // each item is a "directory" having 5 attributes
            // name is the name of the folder
            // fullpath is the full path including the name of the folder
            // size is the size of all files in the folder (in bytes)
            // files is the number of files in the folder
            // subdirs is the count of possible sub directories in the folder
            var elem = new XElement("directory", 
                new XAttribute("name", di.Name), 
                new XAttribute("fullpath",dirName),
                new XAttribute("size", dirsize),
                new XAttribute("files",files.Count()),
                new XAttribute("subdirs",subdirs.Count()));
            foreach (var dinf in subdirs)
            {
                var elemDir = BuildTree(dirName + "\\" + dinf.Name);
                elem.Add(elemDir);
            }
 
            return elem;
        }
    }
}

Ce code peut être utilisé sans passer par un fichier disque puisqu'on récupère le document en mémoire. L'exemple ci-dessous montre comment appeler le code et comment interroger la structure via Linq To Xml pour connaître les répertoires vides (n'ayant ni fichier ni sous répertoire) :

   1:  var d = DirToXml.BuildTreeDocument(@"D:\WpfToolkit");
   2:  d.Save(@"d:\test.xml");
   3:  Console.WriteLine(d.ToString());
   4:  Console.WriteLine(new string('-',60));
   5:   
   6:  var q = from e in d.Descendants("directory")
   7:          where (int) e.Attribute("files") == 0
   8:               && (int)e.Attribute("subdirs") == 0
   9:               orderby (string) e.Attribute("fullpath")
  10:               select e.Attribute("fullpath");
  11:   
  12:  Console.WriteLine("Répertoires vides");
  13:  foreach (var element in q)
  14:    { Console.WriteLine(element); }
  15:  Console.WriteLine(string.Format("{0} répertoires vides",q.Count()));

 

A bientôt pour un prochain billet, so.. Stay Tuned !