从目录树中生成 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 文字。
我的任务是创建 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 文字。