从目录树中生成 XML 时出现递归问题

Recursion issue while generating XML out of a directory tree

我的任务是创建 windows 表单,该表单具有创建文件和文件夹层次结构的 XML 文件的功能。我实际上设法做到了,但是遇到了一些麻烦。这是我的代码:

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

问题是每个文件夹必须有大小和文件夹中有多少文件...我试图计算文件夹的大小,但我不能。我能够显示子文件夹中有多少文件,但所有这些文件都没有显示在 XElement "SubDirectory" 中。如果我删除子目录中的第二个 foreach,则文件甚至不会显示。请帮忙

以下程序将从基目录构建一个 XML 树:

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

结果:

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

备注:

  • 没有递归(这在我看来很好)
  • 计算目录大小可能很长
  • 根据目录,可能有一些 ACL 阻止您访问它
  • 只是一个简单的例子 -> 用你需要的东西扩充它

如果你在 VB 中这样做,它看起来像

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim path As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
    Dim di As New IO.DirectoryInfo(path)
    Dim dirXML As XElement = XMLTreeView(di)

    Dim totalFiles As Integer = (From el In dirXML...<FilesInFolder>
                                    Let tf = Integer.Parse(el.Value)
                                    Select tf).Sum

    Dim totalLength As Long = (From el In dirXML...<Size>
                                Let tl = Long.Parse(el.Value)
                                Select tl).Sum
End Sub

Private Function XMLTreeView(dir As IO.DirectoryInfo) As XElement
    Dim base As XElement = <Directory name=<%= dir.Name %>>
                           </Directory>

    DoSubDirs(dir, base)
    Return base
End Function

Private Sub DoSubDirs(dir As IO.DirectoryInfo, info As XElement)
    For Each di As IO.DirectoryInfo In dir.GetDirectories
        Try
            Dim subXE As XElement = <SubDirectory name=<%= di.Name %>>
                                        <FilesInFolder><%= di.GetFiles.Length.ToString %></FilesInFolder>
                                    </SubDirectory>
            For Each fi As IO.FileInfo In di.GetFiles
                Dim fileXE As XElement = <File name=<%= fi.Name %>>
                                         </File>
                IncludeInfo(fi, fileXE)
                subXE.Add(fileXE)
            Next
            DoSubDirs(di, subXE)
            info.Add(subXE)
        Catch ex As Exception
            'todo errors
            'probably permissions
        End Try
    Next
End Sub

Private Sub IncludeInfo(info As IO.FileInfo, xe As XElement)
    xe.Add(<Attributes><%= info.Attributes %></Attributes>)
    xe.Add(<Size><%= info.Length %></Size>)
    xe.Add(<CreationTime><%= info.CreationTime %></CreationTime>)
    xe.Add(<LastAccess><%= info.LastAccessTime %></LastAccess>)
    xe.Add(<LastModified><%= info.LastWriteTime %></LastModified>)
End Sub

通常递归不是文件系统的问题,因为嵌套级别不是很好。

如果我是 C# 程序员,我会为 XML 使用 VB 模块,因为能够使用 XML 文字。