如何在PowerShell中逐行处理文件作为stream

我正在使用一些多GB的文本文件,并希望使用PowerShell对它们进行一些stream处理。 这是简单的东西,只是parsing每一行,并提取一些数据,然后将其存储在数据库中。

不幸的是, get-content | %{ whatever($_) } get-content | %{ whatever($_) }似乎将pipe道的这个阶段的整个行保留在内存中。 这也是令人惊讶的慢,需要很长时间才能真正阅读。

所以我的问题是两个部分:

  1. 我怎样才能让它一行一行地处理stream,而不是把整个事情缓冲在内存中呢? 我想避免为此使用几个RAM的演出。
  2. 我怎样才能让它跑得更快? 迭代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 } 

http://msdn.microsoft.com/en-us/library/dd383503.aspx

如果你想使用直接的PowerShell检查下面的代码。

 $content = Get-Content C:\Users\You\Documents\test.txt foreach ($line in $content) { Write-Host $line }