Powershell-在foreach循环中使用out文件的性能问题



以下脚本将XML转换为特定的CSV格式,以提供特定的源系统。它运行良好,但性能非常慢。我认为问题是因为Out File正在打开-关闭每一行的文件。有更好的方法吗?

$url = 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.xml'
$result = Invoke-RestMethod  -Uri $url
$elements = $result.Envelope.Cube
foreach($element in $elements)
{
foreach($x in $element.Cube)
{
foreach($y in $x.Cube)
{
$time = $x.time.ToString() -replace "-"
$output =  $time + "`t" + $y.currency.ToString() + "`t" + $y.rate.ToString()
$output | Out-File -Append ".rates.csv"
}
}   
}

我认为问题是因为Out File正在打开-关闭每行的文件

这确实是原因,所以加快命令速度的关键是将所有数据管道传输到单个调用Out-File,您可以通过将foreach循环封装在脚本块({ ... }(中来实现,该脚本块是用&调用的,调用运算符为

& {
foreach ($element in $elements) {
foreach ($x in $element.Cube) {
foreach ($y in $x.Cube) {
$time = $x.time.ToString() -replace "-"
# Synthesize and output the line to save.
$time + "`t" + $y.currency.ToString() + "`t" + $y.rate.ToString()
}
}   
}
} | Out-File .rates.csv

以上内容保留了PowerShell典型的管道行为,将输出行逐个发送到Out-File

假设您的数据已经在内存中,您可以通过在foreach循环中使用$(...)而不是& { ... }来稍微加快操作速度,即使用子表达式运算符$()


也就是说,内存中的数据允许更快的处理:

  • 通过绕过管道,而将所有输出行作为参数传递

  • 此外,假设您正在将文本保存到一个文件中,请使用Set-Content来加快速度。

    • 注意:在Windows PowerShell中,Set-Content的默认编码与Out-File的不同:活动ANSI代码页的编码与UTF-16LE("Unicode"(;在PowerShell[Core]7+中,所有cmdlet都一致默认为无BOM的UTF-8;根据需要使用-Encoding参数
  • 最后,您可以利用PowerShell的成员访问枚举,从foreach循环中消除一个级别的嵌套。

# Adjust -Encoding as needed.
Set-Content -Encoding utf8 .rates.csv -Value $(
foreach ($x in $elements.Cube) {
foreach ($y in $x.Cube) {
$time = $x.time.ToString() -replace "-"
# Synthesize and output the output line.
$time + "`t" + $y.currency.ToString() + "`t" + $y.rate.ToString()
}
}   
)

试试这个:

$url = 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.xml'
$result = Invoke-RestMethod  -Uri $url
$elements = $result.Envelope.Cube
$outputAll = New-Object -TypeName "System.Collections.ArrayList"
foreach($element in $elements)
{
foreach($x in $element.Cube)
{
foreach($y in $x.Cube)
{
$time = $x.time.ToString() -replace "-"
$output =  $time + "`t" + $y.currency.ToString() + "`t" + $y.rate.ToString()
$null = $outputAll.add($output)
}
}   
}
$outputAll | Out-File -Append ".rates.csv"

相关内容

最新更新