我正在处理一些多GB的文本文件,并希望使用PowerShell对它们进行一些流处理。这很简单,只需解析每一行并提取一些数据,然后将其存储在数据库中。
不幸的是,get-content | %{ whatever($_) }
似乎在管道的这个阶段将整个行保留在内存中。它的速度也非常慢,需要花费很长时间来实际阅读。
所以我的问题分为两部分:
get-content
上迭代的PowerShell似乎比C#脚本慢100倍。我希望我在这里做一些愚蠢的事情,比如错过-LineBufferSize
参数或某事......
答案 0 :(得分:89)
如果您真的要处理多GB的文本文件,请不要使用PowerShell。即使你找到了一种方法来阅读它,在PowerShell中处理大量行的速度也会很慢,你无法避免这种情况。即使是简单的循环也很昂贵,比如1000万次迭代(在你的情况下非常真实)我们有:
# "empty" loop: takes 10 seconds
measure-command { for($i=0; $i -lt 10000000; ++$i) {} }
# "simple" job, just output: takes 20 seconds
measure-command { for($i=0; $i -lt 10000000; ++$i) { $i } }
# "more real job": 107 seconds
measure-command { for($i=0; $i -lt 10000000; ++$i) { $i.ToString() -match '1' } }
更新:如果您仍然不害怕,请尝试使用.NET阅读器:
$reader = [System.IO.File]::OpenText("my.log")
try {
for() {
$line = $reader.ReadLine()
if ($line -eq $null) { break }
# process the line
$line
}
}
finally {
$reader.Close()
}
更新2
有关于可能更好/更短代码的评论。使用for
的原始代码没有任何问题,它不是伪代码。但是阅读循环的较短(最短?)变体是
$reader = [System.IO.File]::OpenText("my.log")
while($null -ne ($line = $reader.ReadLine())) {
$line
}
答案 1 :(得分:49)
System.IO.File.ReadLines()
非常适合这种情况。它返回文件的所有行,但允许您立即开始遍历行,这意味着它不必将整个内容存储在内存中。
需要.NET 4.0或更高版本。
foreach ($line in [System.IO.File]::ReadLines($filename)) {
# do something with $line
}
答案 2 :(得分:5)
如果您想直接使用PowerShell,请查看以下代码。
$content = Get-Content C:\Users\You\Documents\test.txt
foreach ($line in $content)
{
Write-Host $line
}