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

sco*_*obi 87 powershell stream

我正在使用一些多GB的文本文件,并希望使用PowerShell对它们进行一些流处理.这很简单,只需解析每一行并提取一些数据,然后将其存储在数据库中.

不幸的是,get-content | %{ whatever($_) }似乎在管道的这个阶段保持整个行集在内存中.它的速度也非常慢,需要花费很长时间才能完全阅读.

所以我的问题是两部分:

  1. 如何让它逐行处理流,而不是将整个事物缓存在内存中?我想避免为此目的使用几次RAM.
  2. 如何让它运行得更快?对a get-content进行迭代的PowerShell 似乎比C#脚本慢100倍.

我希望我在这里做一些愚蠢的事情,比如错过一个-LineBufferSize参数或什么......

Rom*_*min 90

如果您真的要处理多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' } }
Run Code Online (Sandbox Code Playgroud)

更新:如果你仍然不害怕,那么尝试使用.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()
}
Run Code Online (Sandbox Code Playgroud)

更新2

有关于可能更好/更短的代码的评论.原始代码没有任何问题,for它不是伪代码.但是阅读循环的较短(最短?)变体是

$reader = [System.IO.File]::OpenText("my.log")
while($null -ne ($line = $reader.ReadLine())) {
    $line
}
Run Code Online (Sandbox Code Playgroud)

  • 原件有什么问题?这只是一个事实. (8认同)
  • @ BeowulfNode42,我们可以做得更短:`while($ null -ne($ line = $ read.ReadLine())){$ line}`.但这个话题并不是关于这样的事情. (4认同)
  • 仅供参考,PowerShell V3中的脚本编译可以改善这种情况."实际作业"循环从V2上的117秒变为在控制台上键入的V3上的62秒.当我将循环放入脚本并在V3上测量脚本执行时,它下降到34秒. (3认同)
  • 哎呀,应该是 -ne 不相等。那个特定的 do..while 循环有一个问题,即文件末尾的 null 将被处理(在这种情况下是输出)。要解决这个问题,你也可以使用 `for ( $line = $reader.ReadLine(); $line -n​​e $null; $line = $reader.ReadLine() ) { $line }` (2认同)

Des*_*tar 49

System.IO.File.ReadLines()非常适合这种情况.它返回文件的所有行,但允许您立即开始迭代行,这意味着它不必将整个内容存储在内存中.

需要.NET 4.0或更高版本.

foreach ($line in [System.IO.File]::ReadLines($filename)) {
    # do something with $line
}
Run Code Online (Sandbox Code Playgroud)

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

  • 需要注意:.NET Framework - 受支持:4.5,4.因此,在某些计算机上,这可能无法在V2或V1中运行. (6认同)

小智 6

如果您想直接使用PowerShell,请查看以下代码.

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

  • 这就是OP想要摆脱的原因,因为`Get-Content`在大文件上非常慢. (15认同)