我已经成功实现了目录结构到XML脚本,如此处所示。
function GenerateLibraryMap ($path) {
function ProcessChildNode {
param (
$parentNode,
$childPath
)
$dirInfo = [System.IO.DirectoryInfo]::New($childPath)
foreach ($directory in $dirInfo.GetDirectories()) {
$childNode = $xmlDoc.CreateElement('folder')
$childNode.SetAttribute('name', $directory.Name) > $null
$parentNode.AppendChild($childNode) > $null
ProcessChildNode -parentNode:$childNode -childPath:"$childPath\$($directory.Name)"
}
foreach ($file in $dirInfo.GetFiles()) {
$childNode = $xmlDoc.CreateElement('file')
$childNode.SetAttribute('name', $file.Name) > $null
$childNode.SetAttribute('size', $file.Length) > $null
$childNode.SetAttribute('hash', (Get-FileHash -Path:$file.FullName -Algorithm:MD5).Hash) > $null
$parentNode.AppendChild($childNode) > $null
}
}
$xmlDoc = [XML]::New()
$xmlDoc.AppendChild($xmlDoc.CreateProcessingInstruction('xml', 'version="1.0"')) > $null
$rootNode = $xmlDoc.CreateElement('rootDirectory')
$rootNode.SetAttribute('path', $path) > $null
$xmlDoc.AppendChild($rootNode) > $null
ProcessChildNode -parentNode:$rootNode -childPath:$path
$xmlDoc.Save("$path\Tree.xml") > $null
Write-Host "$path\Tree.xml"
}
Measure-Command {
GenerateLibraryMap 'C:\assets\Revit\2020'
}
效果很好,但是在我要测试的文件结构上花费了2分钟以上的时间,这大概只占我实际数据的20%。因此,我正在考虑使用XML流进行重构,因为我知道这样做可能会更快。我发现此reference可以使我入门,但是它仅包含根节点,而没有提及生成层次结构的工作方式。似乎几乎需要跟踪层次结构,以便可以在每个节点上适当地.WriteEndElement
。但这使我的简单递归失败了。我THINK我只需要在第12行的.WriteEndElement
之后简单地单击ProcessChildNode
,但我不确定。
所以,我想我有两个问题...
1:在我深入研究这个兔子洞之前,这会导致明显更快的代码吗?特别是在处理数十个子文件夹中的数千个文件时?还有...
2:有人可以向我指出如何处理递归问题的资源或提供示例吗?否则,我的头会撞到墙上很多。
好的,真的是三个问题...
3:完成这项工作后,由于我正在学习OOP,因此计划将其重构为一类,以提高性能,并作为练习。当我开始钻下一个兔子洞时,是否需要注意一些陷阱?
编辑:有了Mathias的回应和一些挖掘,我得出了这一点。
function GenerateLibraryMap {
param (
[String]$path
)
function ProcessChildNode {
param (
[String]$childPath
)
$dirInfo = [System.IO.DirectoryInfo]::New($childPath)
foreach ($directory in $dirInfo.GetDirectories()) {
$xmlDoc.WriteStartElement('folder')
$xmlDoc.WriteAttributeString('name', $directory.Name)
ProcessChildNode -childPath:"$childPath\$($directory.Name)"
}
foreach ($file in $dirInfo.GetFiles()) {
$xmlDoc.WriteStartElement('file')
$xmlDoc.WriteAttributeString('name', $file.Name)
$xmlDoc.WriteAttributeString('size', $file.Length)
$xmlDoc.WriteAttributeString('hash', (Get-FileHash -Path:$file.FullName -Algorithm:MD5).Hash)
$xmlDoc.WriteEndElement()
}
$xmlDoc.WriteEndElement()
}
$mapFilePath = "$(Split-Path $path -parent)\Tree_Stream.xml"
$xmlSettings = [System.XMl.XmlWriterSettings]::New()
$fileStream = [System.IO.FileStream]::New($mapFilePath, [System.IO.FileMode]::Append, [System.IO.FileAccess]::Write, [System.IO.FileShare]::Read)
$streamWriter = [System.IO.StreamWriter]::New($fileStream)
$xmlSettings.Indent = $true
$xmlSettings.IndentChars = ' '
$xmlSettings.ConformanceLevel = 'Auto'
$xmlDoc = [System.XMl.XmlTextWriter]::Create($fileStream, $xmlSettings)
$xmlDoc.WriteStartDocument()
$xmlDoc.WriteStartElement('rootDirectory')
$xmlDoc.WriteAttributeString('path', $path)
ProcessChildNode -childPath:$path
$xmlDoc.WriteEndElement
$xmlDoc.WriteEndDocument
$xmlDoc.Finalize
$xmlDoc.Flush
$xmlDoc.Close()
Write-Host $mapFilePath
}
CLS
Measure-Command {
GenerateLibraryMap 'C:\assets\Revit\2020'
}
我尝试使用[System.IO.FileStream]
进行尝试,并直接使用文件路径实例化$xmlDoc
(仍然不能100%确保我理解其中的区别)。无论如何,这三种方法彼此之间都只有几秒钟,大约2分钟。因此,在这种情况下似乎没有有意义的区别。如果有人看到提高性能的机会,我将不知所措,但现在,我将着手进行类重构。
这将导致明显更快的代码吗?
也许。找出最简单的方法(无需实际分析当前方法)是继续进行,然后比较结果:)
如何处理递归问题?
容易!
遵循此规则:
function Recurse
{
WriteStartElement
if($shouldRecurse){
Recurse
}
WriteEndElement
}
只要您坚持使用此表格,就可以了。
自从我学习OOP以来,为了提高性能和作为练习,我计划将班级重构为一堂课。当我开始钻下一个兔子洞时,是否需要注意一些陷阱?
可能是吗?
再次,找出最简单的方法就是继续进行下去-如果碰到墙,StackOverflow仍然会在这里:)