在Powershell I';我收到一封“信”;OutOfMemoryException“;使用超过1gb的文件时
在加载到数据仓库之前,我正在进行一些文件清理,遇到了一个文件大小问题:在Powershell I';我收到一封“信”;OutOfMemoryException“;使用超过1gb的文件时,powershell,file-get-contents,Powershell,File Get Contents,在加载到数据仓库之前,我正在进行一些文件清理,遇到了一个文件大小问题: (Get-Content -path C:\Workspace\workfile\myfile.txt -Raw) -replace '\\"', '"' | Set-Content C:\Workspace\workfile\myfileCLEAN.txt 我的文件大约是2GB。我收到以下错误,不确定如何更正 获取内容:“System.OutOfMemoryException”类型的异常为 扔 我不是
(Get-Content -path C:\Workspace\workfile\myfile.txt -Raw) -replace '\\"', '"' | Set-Content C:\Workspace\workfile\myfileCLEAN.txt
我的文件大约是2GB。我收到以下错误,不确定如何更正
获取内容:“System.OutOfMemoryException”类型的异常为
扔
我不是一个编码员,但我喜欢学习,所以我要建立自己的数据仓库。因此,如果您确实响应了,请记住我的经验级别:)
获取内容
将整个文件加载到内存中
尝试逐行处理以提高内存利用率
$infile = "C:\Workspace\workfile\myfile.txt"
$outfile = "C:\Workspace\workfile\myfileCLEAN.txt"
foreach ($line in [System.IO.File]::ReadLines($infile)) {
Add-Content -Path $outfile -Value ($line -replace '\\"','"')
}
Get Content-Raw
使PowerShell将整个文件读取为单个字符串
.NET无法在内存中存储大小超过2GB的单个对象,并且字符串中的每个字符占用2个字节,因此在读取前10亿个字符(大致相当于1GB ASCII编码的文本文件)后,它达到了内存限制
卸下-Raw
开关,-replace
完全能够同时操作多个输入字符串:
(Get-Content -path C:\Workspace\workfile\myfile.txt) -replace '\"', '"' | Set-Content C:\Workspace\workfile\myfileCLEAN.txt
请注意,-replace
是一个正则表达式运算符,如果要从字符串中删除\
,则需要对其进行转义:
(Get-Content -path C:\Workspace\workfile\myfile.txt) -replace '\\"', '"' | Set-Content C:\Workspace\workfile\myfileCLEAN.txt
虽然这会起作用,但仍然会很慢,因为在应用-replace
并写入输出文件之前,我们仍在将>2GB的数据加载到内存中
相反,您可能希望通过管道将输出从Get Content
传输到ForEach对象
cmdlet:
Get-Content -path C:\Workspace\workfile\myfile.txt |ForEach-Object {
$_ -replace '\\"','"'
} |Set-Content C:\Workspace\workfile\myfileCLEAN.txt
这允许Get Content
在完成文件读取之前开始推送输出,因此PowerShell不再需要像以前那样分配大量内存,从而加快执行速度。- 逐行读取文本文件(无需将整个文件加载到内存中)的一种有效方法是使用带有
参数的语句-file
- 编写文本文件的有效方法是使用实例
- 正如Mathias在中指出的,由于正则表达式的转义规则,使用基于正则表达式的逐字
实际上会单独替换\“
。虽然您可以使用”
解决这个问题,但在本例中,一个更简单、性能更好的替代方法是使用“\\”
类型的方法,该方法对文本子字符串进行操作[string]
# Note: Be sure to use a *full* path, because .NET's working dir. usually
# differs from PowerShell's.
$streamWriter = [System.IO.StreamWriter]::new('C:\Workspace\workfile\myfileCLEAN.txt')
switch -File C:\Workspace\workfile\myfile.txt {
default { $streamWriter.WriteLine($_.Replace('\"', '"')) }
}
$streamWriter.Close()
注意:如果您使用的是旧版本的Windows PowerShell,即版本4或更低,请使用New Object System.IO.StreamWriter'C:\Workspace\workfile\myfileCLEAN.txt'
而不是
[System.IO.StreamWriter]::新建('C:\Workspace\workfile\myfileCLEAN.txt')
不要加载整个文件…一行一行地加载它,并在每一行上进行替换。然后使用添加内容
将结果发送到新文件。获取内容
仅在使用-Raw
开关或将调用包含在(…)
中时才将整个文件加载到内存中。[System.IO.file]::ReadLines()
是读取文件的一种有效方法,在循环中使用添加内容
会在每次迭代中打开和关闭输出文件,这会抵消性能优势。这可以工作,但速度与使用Get Content一样慢。我看到的唯一优势是占用内存少,而且我可以更轻松地监控进度。这确实有效,但非常简单速度慢,2GB文件的处理速度快了将近一个小时。有没有任何帮助加快处理速度的提示?谢谢你指出。我升级到了v5,哇!这非常好而且非常快:)非常感谢!