【问题标题】:Recursion issue while generating XML out of a directory tree从目录树生成 XML 时的递归问题
【发布时间】:2017-04-21 22:25:15
【问题描述】:

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

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“子目录”中。如果我删除 subdir 中的第二个 foreach,则甚至没有显示文件。请帮忙。

【问题讨论】:

  • 好问题,你应该给它一个更好的标题!
  • 第一个问题...:) 不知道如何命名...
  • 好的,等一下,为你做点什么!

标签: c# xml xelement


【解决方案1】:

以下程序将从基础目录构建 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>

注意事项:

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

【讨论】:

  • 真的很好,谢谢你,至少你解决了我的尺寸问题。但是我做的程序必须是windows形式的。这可以应用于它吗?并且仍然需要一个文件夹中有多少个文件...
  • 对任何非标准(LINQ、XML)都没有依赖关系,即您可以在任何拥有 .NET 4 的地方使用代码,因此在 Forms 中它可以工作。 (我刚刚添加了文件夹/文件数)
  • 我刚试了一下,效果很好。你是救命恩人!!! :) 再次感谢您!
【解决方案2】:

如果你在 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 文字。

【讨论】:

  • 在 C# 中不可能使用 XML 文字!
  • 我知道,它们很方便。不知道为什么他们被排除在 C# 之外。
猜你喜欢
  • 2014-08-14
  • 2012-03-04
  • 1970-01-01
  • 1970-01-01
  • 2018-11-06
  • 2022-11-14
  • 2020-01-10
  • 2011-01-22
  • 1970-01-01
相关资源
最近更新 更多