我已经成功地将目录结构实现为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进行重构,因为我知道这可能要快得多。我找到了这个参考文献来启动它,但是它只包含根节点,没有提到生成层次结构是如何工作的。看起来,您几乎需要跟踪层次结构,以便能够在每个节点上适当地进行.WriteEndElement。但这让我的简单递归崩溃了。我想我只需要简单地在第12行的.WriteEndElement之后使用ProcessChildNode,但我不确定。
我想我有两个问题..。
他说:在我进入这个兔子洞之前,这会导致明显更快的代码吗?尤其是在处理成千上万个子文件夹中的文件时?还有..。
他说:有人能告诉我如何处理递归问题的资源,或者提供一个例子吗?我有一种感觉,如果不这样的话,我的头会撞到墙上。
好吧,真的有三个问题。
他说:一旦我有了这个工作,我计划重构到一个班级,这既是为了提高性能,也是作为一个练习,因为我正在学习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分钟左右。因此,在这种情况下,似乎没有什么有意义的区别。如果有人看到了提高成绩的机会,我会全神贯注地听,但现在我将把重构推进到课堂上。
编辑2:嗯,我实现了基于类的方法,像这样.
class GenerateLibraryMap {
# Properties
[XML.XMLDocument]$XML = [XML]::New()
[String]$MapFilePath
# Constructor
GenerateLibraryMap ([String]$path) {
$this.MapFilePath = "$(Split-Path $path -parent)\Tree_Class.xml"
$this.XML.AppendChild($this.XML.CreateProcessingInstruction('xml', 'version="1.0"')) > $null
$rootNode = $this.XML.CreateElement('rootDirectory')
$rootNode.SetAttribute('path', $path) > $null
$this.XML.AppendChild($rootNode) > $null
$this.ProcessChildNode($rootNode, $path)
$this.XML.Save($this.MapFilePath)
}
# Method
[Void] ProcessChildNode([XML.XMLElement]$parentNode, [String]$childPath) {
$dirInfo = [System.IO.DirectoryInfo]::New($childPath)
foreach ($directory in $dirInfo.GetDirectories()) {
$childNode = $this.XML.CreateElement('folder')
$childNode.SetAttribute('name', $directory.Name)
$parentNode.AppendChild($childNode)
$this.ProcessChildNode($childNode, "$childPath\$($directory.Name)")
}
foreach ($file in $dirInfo.GetFiles()) {
$childNode = $this.XML.CreateElement('file')
$childNode.SetAttribute('name', $file.Name)
$childNode.SetAttribute('size', $file.Length)
$childNode.SetAttribute('hash', (Get-FileHash -Path:$file.FullName -Algorithm:MD5).Hash)
$parentNode.AppendChild($childNode)
}
}
}
Measure-Command {
$xml = [GenerateLibraryMap]::New('C:\assets\Revit\2020')
}
Write-Host "$($xml.MapFilePath)"花同样的时间。但是无论如何都是教育性的。看起来,基于流的版本的内存效率略高一些。希望有人能找到有用的结果。
发布于 2020-05-21 15:53:45
这会导致明显更快的代码吗?
也许吧。找出答案的最简单方法(不实际分析当前的方法)就是继续做下去,然后比较结果:)
如何处理递归问题?
简单!
遵循以下规则:
function Recurse
{
WriteStartElement
if($shouldRecurse){
Recurse
}
WriteEndElement
}只要你坚持这份表格,你就会没事的。
由于我正在学习OOP,我计划将其重构到一个类中,这既是为了提高性能,也是作为一个练习。当我从下一个兔子洞开始的时候,我有什么需要注意的问题吗?
可能是吧?
同样,最简单的方法就是继续做下去--如果你撞到墙的时候,StackOverflow仍然会在这里:)
https://stackoverflow.com/questions/61937366
复制相似问题