【问题标题】:OutOfMemoryException when running my PowerShell script运行我的 PowerShell 脚本时出现 OutOfMemoryException
【发布时间】:2011-11-15 05:54:13
【问题描述】:

这是我用来将“segment99”添加到文件夹内所有文本文件(一个一个)开头的 PowerShell 脚本:

Set Environmental Variables:

$PathData = '<<ESB_Data_Share_HSH>>\RwdPnP'

Go to each text file in the specified folder and add header to the file:

Get-ChildItem $PathData -filter 'test_export.txt'|%{

$content = '"segment99" ' + [io.file]::ReadAllText($_.FullName)
[io.file]::WriteAllText(($_.FullName -replace '\.txt$','_99.txt'),$content)

}

这给了我以下错误:

Error: Exception calling "ReadAllText" with "1" argument(s): "Exception of type 'Syste
Error: m.OutOfMemoryException' was thrown."
Error: At D:\apps\MVPSI\JAMS\Agent\Temp\JAMSTemp13142.ps1:17 char:51
Error: + $content = '"segment99" ' + [io.file]::ReadAllText <<<< ($_.FullName)
Error:     + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
Error:     + FullyQualifiedErrorId : DotNetMethodException
Error:

我在一个包含 20 个文件的文件夹上运行此代码,每个文件超过 2 GB。

我该如何解决这个问题?

【问题讨论】:

    标签: powershell


    【解决方案1】:

    将头文件 + 大文件复制到新文件将不太容易出现内存不足异常(对于该大小的文件):

    $header = '"segment99"'
    $header | out-file header.txt -encoding ASCII
    $pathdata = "."
    Get-ChildItem $PathData -filter 'test_export.txt' | %{
      $newName = "{0}{1}{2}" -f $_.basename,"_99",$_.extension
      $newPath = join-path (split-path $_.fullname) $newname
      cmd /c copy /b "header.txt"+"$($_.fullname)" "$newpath"
    }
    

    【讨论】:

    • @RomanKuzmin 我忘记了输出文件 cmdlet 中的编码。谢谢你抓。在一个大文件 (> 2GB) 上测试并且运行良好(
    • 要明确一点,头文件的编码应该和test_export.txt文件的编码一致。
    • 我喜欢这个解决方案,它可能是最快的,而且由于文件很大(大约 2GB),这很重要。但是header应该写成[IO.File]::WriteAllText('header.txt', $header),即后面没有新行(注意:原代码是把header插入到第一行,而不是添加新行)。
    【解决方案2】:

    这不是最佳代码,但它无需将所有文本读取到内存即可解决任务:它将标题添加到第一行,然后输出其他行。另外请注意,如果输入文件为空,它什么也不做。

    Get-ChildItem $PathData -Filter 'test_export.txt' | %{
        $header = $true
        Get-Content $_.FullName | .{process{
            if ($header) {
                '"segment99" ' + $_
                $header = $false
            }
            else {
                $_
            }
        }} | Set-Content ($_.FullName -replace '\.txt$', '_99.txt')
    }
    

    【讨论】:

    • 这就是我想建议的。无论如何,为什么.{process{ 行?我想一个 foreach-object 会起作用吗?
    • 是的,ForEach-Object.{process{..}} 相同(基本上),但要慢得多。当它大约是 2GB 时,这很重要。
    • 哦..这是什么.{符号?
    • . 是运算符“在当前范围内调用”。 . {} 是“调用脚本块”。每个脚本块可能有beginprocessend 块。我们的脚本块有process。因此,最后我们得到. { process{} }
    • 感谢您的解释...应该猜到了,看起来很奇怪:)
    猜你喜欢
    • 2015-06-21
    • 1970-01-01
    • 2022-01-08
    • 1970-01-01
    • 2014-07-23
    • 2016-09-13
    • 1970-01-01
    • 2019-11-04
    • 1970-01-01
    相关资源
    最近更新 更多