如何在PowerShell中逐行处理文件作为stream
我正在使用一些多GB的文本文件,并希望使用PowerShell对它们进行一些stream处理。 这是简单的东西,只是parsing每一行,并提取一些数据,然后将其存储在数据库中。
不幸的是, get-content | %{ whatever($_) }
get-content | %{ whatever($_) }
似乎将pipe道的这个阶段的整个行保留在内存中。 这也是令人惊讶的慢,需要很长时间才能真正阅读。
所以我的问题是两个部分:
- 我怎样才能让它一行一行地处理stream,而不是把整个事情缓冲在内存中呢? 我想避免为此使用几个RAM的演出。
- 我怎样才能让它跑得更快? 迭代
get-content
PowerShell似乎比C#脚本慢了100倍。
我希望有一些愚蠢的,我在这里做,就像缺less一个-LineBufferSize
参数或…
如果您真的要处理几千兆字节的文本文件,那么请不要使用PowerShell。 即使您find了一种方法来读取它,无论如何,在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 }
System.IO.File.ReadLines()
非常适合这种情况。 它返回一个文件的所有行,但是可以立即开始遍历行,这意味着它不需要将整个内容存储在内存中。
需要.NET 4.0或更高版本。
foreach ($line in [System.IO.File]::ReadLines($filename)) { # do something with $line }
如果你想使用直接的PowerShell检查下面的代码。
$content = Get-Content C:\Users\You\Documents\test.txt foreach ($line in $content) { Write-Host $line }