Search code examples
c#xmlxelement

Recursion issue while generating XML out of a directory tree


I have a task to create windows form with functionality to create an XML file of hierarchy of files and folders. I actually managed to do it, but have some trouble. Here is my code:

public static XElement xmlTreeView(DirectoryInfo dir)
    {
        XDocument xmlDocument = new XDocument(
            new XDeclaration("1.0", "utf-8", "yes"),
            new XComment("Create an XML file containing complete hierarchy of files and folders for a specified folder"));

        var info = new XElement("Directory", new XAttribute("name", dir.Name));

        foreach (var subDir in dir.GetDirectories())
        {
            info.Add(new XElement("SubDirectory", new XAttribute("name", subDir.Name),
                new XElement("FilesInFolder", subDir.GetFiles().Length)));
            foreach (var file in subDir.GetFiles())
                {
                    info.Add(new XElement("File", new XAttribute("name", file.Name),
                        new XElement("Size", file.Length),
                        new XElement("CreationTime", file.CreationTime),
                        new XElement("LastAccess", file.LastAccessTime),
                        new XElement("LastModified", file.LastWriteTime)));
            }
        }

        foreach (var file in dir.GetFiles())
        {
            info.Add(new XElement("File", new XAttribute("name", file.Name),
                new XElement("Size", file.Length),
                new XElement("CreationTime", file.CreationTime),
                new XElement("LastAccess", file.LastAccessTime),
                new XElement("LastModified", file.LastWriteTime)));
        }



        return info;
    }

the problem is that each folder must have the size and how many files are located in the folder...I tried to calculate the size of the folder, but I couldn't. I was able to show how many files have in subfolder, but all of these files are not shown inside XElement "SubDirectory". If I remove second foreach in subdir, than files not even shown. Help please.


Solution

  • The following program will build an XML tree out of a base directory:

    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Xml.Linq;
    
    namespace ConsoleApplication1
    {
        internal class Program
        {
            private static void Main(string[] args)
            {
                ConvertToXml(@"C:\test");
            }
    
            private static void ConvertToXml(string baseDirectory)
            {
                var root = new XElement("Root");
    
                var queue = new Queue<KeyValuePair<XElement, string>>();
                queue.Enqueue(new KeyValuePair<XElement, string>(root, baseDirectory));
    
                while (queue.Any())
                {
                    var pair = queue.Dequeue();
                    var path = pair.Value;
                    var element = pair.Key;
                    var directories = Directory.GetDirectories(path);
                    var files = Directory.GetFiles(path);
    
                    element.Add(
                        new XAttribute("Files", files.Length.ToString()),
                        new XAttribute("Directories", directories.Length.ToString()));
    
                    foreach (var directory in directories)
                    {
                        var directoryInfo = new DirectoryInfo(directory);
                        var directoryElement = new XElement("Directory",
                            new XAttribute("Name", directoryInfo.Name),
                            new XAttribute("Size", GetDirectorySize(directory)));
    
                        element.Add(directoryElement);
                        queue.Enqueue(new KeyValuePair<XElement, string>(directoryElement, directory));
                    }
    
                    foreach (var file in files)
                    {
                        var fileInfo = new FileInfo(file);
                        var fileElement = new XElement("File",
                            new XAttribute("Name", fileInfo.Name),
                            new XAttribute("Size", fileInfo.Length));
                        element.Add(fileElement);
                    }
                }
    
                var xml = root.ToString();
            }
    
            private static long GetDirectorySize(string path)
            {
                long length = 0;
    
                var queue = new Queue<string>(new[] {path});
    
                while (queue.Any())
                {
                    var value = queue.Dequeue();
    
                    var files = Directory.GetFiles(value);
                    length += files.Sum(s => new FileInfo(s).Length);
    
                    var directories = Directory.GetDirectories(value);
                    foreach (var directory in directories)
                        queue.Enqueue(directory);
                }
    
                return length;
            }
        }
    }
    

    Result:

    <Root Files="0" Directories="1">
      <Directory Name="root" Size="444" Files="1" Directories="2">
        <Directory Name="folder1" Size="148" Files="1" Directories="0">
          <File Name="document1.txt" Size="148" />
        </Directory>
        <Directory Name="folder2" Size="185" Files="1" Directories="0">
          <File Name="document2.txt" Size="185" />
        </Directory>
        <File Name="readme.txt" Size="111" />
      </Directory>
    </Root>
    

    Notes:

    • no recursion (which is good IMO)
    • computing a directory size can be long
    • depending the directory, there might be some ACL preventing you accessing it
    • just a trivial example -> augment it with what you need