如何解决Powershell - 在 foreach 循环中使用输出文件的性能问题
以下脚本将 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
循环包装在您使用 { ... }
调用的 script block (&
) 中,call operator:
& {
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
来稍微加快操作速度,即通过使用 $()
,subexpression operator。
也就是说,内存中数据可以实现更快的处理:
-
绕过管道,而是将所有输出行作为参数传递。
-
此外,考虑到您将文本保存到文件中,使用
Set-Content
可以加快速度。- 注意:在 Windows PowerShell 中,
Set-Content
的默认编码与Out-File
的不同:活动 ANSI 代码页的编码与 UTF-16LE(“Unicode” );在 PowerShell [Core] 7+ 中,所有 cmdlet 始终默认为无 BOM 的 UTF-8;根据需要使用-Encoding
参数。
- 注意:在 Windows PowerShell 中,
-
最后,您可以利用 PowerShell 的 member enumeration 从
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"
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。