XMLWriter和递归

问题描述 投票:0回答:1

我已经成功实现了目录结构到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分钟。因此,在这种情况下似乎没有有意义的区别。如果有人看到提高性能的机会,我将不知所措,但现在,我将着手进行类重构。

powershell recursion xmlwriter
1个回答
0
投票

这将导致明显更快的代码吗?

也许。找出最简单的方法(无需实际分析当前方法)是继续进行,然后比较结果:)

如何处理递归问题?

容易!

遵循此规则:

  • 打开节点的递归函数调用也应该负责关闭它-换句话说,递归函数的结构应类似于(伪代码):
function Recurse
{
    WriteStartElement
    if($shouldRecurse){
      Recurse
    }
    WriteEndElement
}

只要您坚持使用此表格,就可以了。

自从我学习OOP以来,为了提高性能和作为练习,我计划将班级重构为一堂课。当我开始钻下一个兔子洞时,是否需要注意一些陷阱?

可能是吗?

再次,找出最简单的方法就是继续进行下去-如果碰到墙,StackOverflow仍然会在这里:)

© www.soinside.com 2019 - 2024. All rights reserved.