【发布时间】:2011-05-10 16:12:55
【问题描述】:
我正在处理一些数千兆字节的文本文件,并希望使用 PowerShell 对它们进行一些流处理。这很简单,只需解析每一行并提取一些数据,然后将其存储在数据库中。
不幸的是,get-content | %{ whatever($_) } 似乎将管道此阶段的整个行集保留在内存中。它的速度也出奇的慢,需要很长时间才能真正读完。
所以我的问题是两个部分:
- 如何让它逐行处理流,而不是将整个内容缓存在内存中?我想避免为此使用几 GB 的 RAM。
- 如何让它运行得更快? PowerShell 迭代
get-content似乎比 C# 脚本慢 100 倍。
我希望我在这里做了一些愚蠢的事情,比如缺少 -LineBufferSize 参数或其他东西......
【问题讨论】:
-
要加快
get-content的速度,请将 -ReadCount 设置为 512。注意此时,Foreach 中的 $_ 将是一个字符串数组。 -
不过,我还是会接受 Roman 的建议,即使用 .NET 阅读器——要快得多。
-
出于好奇,如果我不关心速度而只关心内存会怎样?我很可能会接受 .NET 阅读器的建议,但我也很想知道如何防止它在内存中缓冲整个管道。
-
为了尽量减少缓冲,请避免将
Get-Content的结果分配给变量,因为这会将整个文件加载到内存中。默认情况下,在管道中,Get-Content一次处理一行文件。只要您不累积结果或使用内部累积的 cmdlet(如 Sort-Object 和 Group-Object),那么内存命中应该不会太糟糕。 Foreach-Object (%) 是一种处理每一行的安全方法,一次处理一个。 -
@dwarfsoft 这没有任何意义。 -End 块仅在所有处理完成后运行一次。您可以看到,如果您尝试使用
get-content | % -End { },那么它会抱怨,因为您没有提供进程块。所以它不能默认使用-End,它必须默认使用-Process。并尝试1..5 | % -process { } -end { 'q' }并看到结束块只发生一次,如果脚本块默认为 -End...,通常的gc | % { $_ }将不起作用...
标签: powershell stream