我目前有以下代码行。
(Get-Content 'file.txt') |
ForEach-Object {$_ -replace '"', ''} |
Set-Content 'file.txt'
这在测试时有效,但现在我尝试在真实数据文件(13 GB)上使用它,这个使用Get-Content的过程导致Powershell消耗大量RAM并最终消耗所有可用RAM机器。
有没有更好的方法可以在没有相同开销的情况下实现相同的结果?
似乎我的做法与最佳做法相反,但不确定还有什么比上面更清洁/更少RAM。
答案 0 :(得分:6)
使用流来读取文件,然后它不会将其全部放入内存,您也可以使用流来写入输出。这应该很好,并保持内存使用率下降:
$file = New-Object System.IO.StreamReader -Arg "c:\test\file.txt"
$outstream = [System.IO.StreamWriter] "c:\test\out.txt"
while ($line = $file.ReadLine()) {
$s = $line -replace '"', ''
$outstream.WriteLine($s)
}
$file.close()
$outstream.close()
答案 1 :(得分:5)
您的问题不是由Get-Content
引起的,而是由您在表达式中运行语句(即在括号中)引起的。像这样运行Get-Content
是允许管道将数据写回同一文件的便捷方式。但是,这种方法的缺点是在将数据传递到管道之前将整个文件读入内存(否则,当Set-Content
尝试将数据写回到文件时,文件仍将打开以供读取。)< / p>
要处理大型文件,必须删除括号,并将输出写入您之后重命名的临时文件。
Get-Content 'C:\path\to\file.txt' |
ForEach-Object {$_ -replace '"', ''} |
Set-Content 'C:\path\to\temp.txt'
Remove-Item 'C:\path\to\file.txt'
Rename-Item 'C:\path\to\temp.txt' 'file.txt'
这样做可以避免您观察到的内存耗尽。通过将读取计数增加为@mjolinor建议(在我的测试中将执行时间减少到大约40%),可以进一步加快处理速度。
为了获得更好的效果,请使用StreamReader
和StreamWriter
@campbell.rw建议的方法:
$reader = New-Object IO.StreamReader 'C:\path\to\file.txt'
$writer = New-Object IO.StreamWriter 'C:\path\to\temp.txt'
while ($reader.Peek() -ge 0) {
$line = $reader.ReadLine().Replace('"', '')
$writer.WriteLine($line)
}
$reader.Close(); $reader.Dispose()
$writer.Close(); $writer.Dispose()
Remove-Item 'C:\path\to\file.txt'
Rename-Item 'C:\path\to\temp.txt' 'file.txt'
答案 2 :(得分:1)
这应该比逐行处理更快,并且仍然可以控制内存消耗:
Get-content 'file.txt' -ReadCount 5000 |
foreach-object {$_ -replace '"', '' |
add-content 'newfile.txt' }