首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >[System.IO.File]::ReadAlltext($File) OutOfMemory错误

[System.IO.File]::ReadAlltext($File) OutOfMemory错误
EN

Stack Overflow用户
提问于 2020-12-15 22:25:35
回答 2查看 464关注 0票数 0

在将zipe文件(1.6gb)转换为字节后,我试图将zip文件上传到Nexus存储库。问题是当它读取zip文件的字节时,如果文件大小很大,就会抛出system.outofmemory错误。如果它只有3-600mb,它不会抛出错误,有办法读取字节并避免oufofmemory错误吗?

使用"1“参数调用"ReadAllText”的异常:“类型为'System.OutOfMemoryException‘的异常被抛出。”

$fileBin = System.IO.File::ReadAlltext($File)

代码语言:javascript
复制
Function Upload-File-To-Nexus {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $True )][ValidateNotNullOrEmpty()][string]$File, # aka File
        [parameter(Mandatory = $True )][ValidateNotNullOrEmpty()][string]$Repository,
        [parameter(Mandatory = $True )][ValidateNotNullOrEmpty()][string]$Directory,
        [Parameter(Mandatory = $False)][ValidateNotNullOrEmpty()][string]$FileName # destination filename, which can be derived from uploaded file
    )

    Begin {

        $token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("fahq-ra-build:tEDlCI=0m9CES8l*lk?b"))
        $header = @{authorization = "Basic $token" }
        
        $Uri = "https://nexus-arps.corp.firstam.com/service/rest/v1/components?repository=${Repository}"
        $boundary = [System.Guid]::NewGuid().ToString()
        $LF = "`r`n"
    }

    Process {
        If (!($FileName -ne $Null -And $FileName -ne "")) {
            # if filename is null, then just use the filename from the input file
            $FileName = Split-Path $File -Leaf
        }
        Try { $fileBin = [System.IO.File]::ReadAlltext($File) }
        Catch { 
            throw $_.exception
            Throw "Unable to read file $File. Aborted." 
        }
        $bodyLines = (
            "--${boundary}",
            "Content-Disposition: form-data; name=`"raw.directory`"",
            "",
            "${Directory}",
            "--${boundary}",
            "Content-Disposition: form-data; name=`"raw.asset1`"; filename=`"${FileName}`"",
            "Content-Type: application/octet-stream",
            "",
            $file,
            "",
            "--${boundary}",
            "Content-Disposition: form-data; name=`"raw.asset1.filename`"",
            "",
            "${FileName}",
            "--${boundary}--",
            ""
        ) -join $LF
        $Response = Invoke-WebRequest -Uri $Uri -Method "POST" -Headers $header -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $bodyLines
        If ($Response.StatusCode -ge 200 -And $Response.StatusCode -lt 300) {
            $Output = "https://${Server}/repository/${repository}/${directory}/${FileName}" -Replace "//", "/"
            Write-Output $Output
        }
        Else {
            Write-Output $Response
        }
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-12-15 22:32:06

考虑到您没有处理基于文本的文件,您可能是指.ReadAllBytes()

但是,您不必将该文件加载到内存中--使用Invoke-WebRequest-InFile参数来指定要上载的文件。

票数 3
EN

Stack Overflow用户

发布于 2020-12-15 22:34:01

IIRC,ReadAllBytes()的工作方式是它不知道或不预先查找文件大小。相反,它猜测产生的字节数组的缓冲区大小。当猜测失败时,它会加倍猜测,分配一个新数组,并复制到目前为止读取的内容。这会重复执行,直到加载文件为止。

那么,您不仅可以从实际耗尽内存中获得OutOfMemory,而且还可以从额外的缓冲区中运行当前进程中的地址空间,在该缓冲区中,默认情况下,单个进程仅限于2GB。

如果这听起来很糟糕,而且效率很低,那么您是对的,而且RealAllBytes()实际上只对小文件有用。

在处理较大的文件时,您需要使用流API,例如File.OpenRead()。在这里,您可以检查文件的实际大小,使用它分配确切的字节数组,然后一次读取一个小块(例如,4K)。

更好的是,由于您已经在使用Invoke-WebRequest,您知道它是supports a -InFile argument吗?它可以用于上传文件而不将整个文件加载到内存中?

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65314577

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档