I believe the issue is because Out-File is opening - closing the file for every line
That is indeed the reason, so the key to speeding up your command is to pipe all data to a single invocation of Out-File
, which you can achieve by wrapping your foreach
loop in a script block ({ ... }
) that you invoke with &
, the 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
The above preserves PowerShell's typical streaming pipeline behavior, sending output lines one by one to Out-File
.
Given that your data is already in memory anyway, you can speed up the operation a little by using $(...)
rather than & { ... }
around your foreach
loop, i.e. by using $()
, the subexpression operator.
That said, in-memory data allows even faster processing:
Through bypassing the pipeline and instead passing all output lines as an argument.
Additionally, given that you're saving text to a file, by using Set-Content
to speed things up a bit.
- Note: In Windows PowerShell,
Set-Content
's default encoding differs from Out-File
's: the active ANSI code page's encoding vs. UTF-16LE ("Unicode"); in PowerShell [Core] 7+, all cmdlets consistently default to BOM-less UTF-8; use the -Encoding
parameter as needed.
Finally, you can eliminate one level of nesting from your foreach
loops by taking advantage of PowerShell's member-access enumeration.
# 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()
}
}
)