Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Powershell FTP发送大文件系统。OutOfMemoryException_Powershell_Ftp_Out Of Memory - Fatal编程技术网

Powershell FTP发送大文件系统。OutOfMemoryException

Powershell FTP发送大文件系统。OutOfMemoryException,powershell,ftp,out-of-memory,Powershell,Ftp,Out Of Memory,我有一个部分基于此处的脚本: 这一切对于小文件来说都非常好,但我正试图使用它使我们用于将access mdb文件导出到只有ftp的客户端的过程更加健壮 我的第一个测试涉及一个10MB的文件,在获取内容阶段遇到System.OutOfMemoryException 在获取尝试期间,powershell ISE的使用率接近2GIG 这是一个完整的脚本示例(请温柔一点,我对它还比较陌生): 我不能将代码放在注释中,所以,多亏了keith的指针,我将文件访问位移到了底部,以便将其与其他文件链接起来,就像

我有一个部分基于此处的脚本:

这一切对于小文件来说都非常好,但我正试图使用它使我们用于将access mdb文件导出到只有ftp的客户端的过程更加健壮

我的第一个测试涉及一个10MB的文件,在获取内容阶段遇到System.OutOfMemoryException

在获取尝试期间,powershell ISE的使用率接近2GIG

这是一个完整的脚本示例(请温柔一点,我对它还比较陌生):

我不能将代码放在注释中,所以,多亏了keith的指针,我将文件访问位移到了底部,以便将其与其他文件链接起来,就像这样

trap [Exception]{
    $script:succeeded = $false
    $script:errorMessage = $_.Exception.Message
    Add-Content $logFile $((get-Date -format "yyyy-MM-dd hh:mm:ss") + "|1|Check File Connection|" + $_.Exception.Message)
    $sourceStream.Close()
    $sourceStream.Dispose()
    #write-host $((get-Date -format "yyyy-MM-dd hh:mm:ss") + "|1|Attempt to open file|" + $_.Exception.Message)
    #write-host $("TRAPPED: " + $_.Exception.GetType().FullName)
    exit
}
$sourceStream = New-Object IO.FileStream ($(New-Object System.IO.FileInfo $sourceFile),[IO.FileMode]::Open)
[byte[]]$readbuffer = New-Object byte[] 1024

# get the request stream, and write the bytes into it
$rs = $ftprequest.GetRequestStream()
do{
    $readlength = $sourceStream.Read($readbuffer,0,1024)
    $rs.Write($readbuffer,0,$readlength)
} while ($readlength -ne 0)
我只需要找出原因:调用带有“0”参数的“GetResponse”异常:“无法访问已处理的对象。 每隔一次我运行它。这是在ISE中运行它的一个怪癖,还是我在初始声明或最终处理方面做了一些重大错误

完成后我将发布完整的最终脚本,因为我认为这将是一个很好的ftp导出示例,包含错误捕获和日志记录


好的,这是完整的脚本。Dispose已被编辑,但无论是否运行,脚本在5分钟内都会收到一条消息,告诉我无法使用disposed对象,或者告诉我getResponse()已生成一个错误(226)文件传输(在ISE中运行)。虽然这在正常操作期间不会出现问题,但我希望正确地注销FTP会话,并在脚本末尾清理资源,并确保根据需要正确声明它们

#####
# User variables to control the script
#####

# How many times connection will be re-tried
$connectionTries = 5
#time between tries in seconds
$connectionTryInterval = 1
#Where to log the output
$logFile = "D:\MyPath\ftplog.txt"
#maximum log file size in KB before it is archived
$logFileMaxSize = 500
#log to file or console - #true=log to file, #false = log to console
$logToFile=$false

#formatted date part for the specific file to transfer
#This is appended to the filename base. Leave as "" for none
$datePart = ""
#base part of the file name
$fileNameBase = "MyFile"
#file extension
$fileExtension = ".mdb"
#location of the source file (please include trailing backslash)
$sourceLocation = "D:\MyPath\"

#location and credentials of the target ftp server
$userName = "iamafish"
$password = "ihavenofingers"
$ftpServer = "10.0.1.100"

######
# Main Script
#####

function logEntry($entryType, $section, $message)
{
    #just to make a one point switch for logging to console for testing
    # $entryType: 0 = success, 1 = Error
    # $section: The section of the script the log entry was generated from
    # $message: the log message

    #This is pipe separated to fit in with my standard MSSQL linked flat file schema for easy querying
    $logString = "$(get-Date -format "yyyy-MM-dd hh:mm:ss")|$entryType|$section|$message"

    if($script:logtoFile)
    {
        Add-Content $logFile $logString
    }
    else
    {
        write-host $logString
    }
}

#If there is a log file and it is longer than the declared limit then archive it with the current timestamp
if (test-path $logfile)
{
    if( $((get-item $logFile).Length/1kb) -gt $logFileMaxSize)
    {
        write-host $("archiving log to ftplog_" + (get-date -format yyyyMMddhhmmss) + ".txt")
        rename-item $logFile $("ftplog_" + (get-date -format yyyyMMddhhmmss) + ".txt")
        New-Item $logFile -type file
    }
}
else
{
    New-Item $logFile -type file
}


#contruct source file and destination uri
$fileName = $fileNameBase + $datePart + $fileExtension
$sourceFile = $sourceLocation + $fileName
$destination = "ftp://" + $ftpServer + "/" + $fileName


#Check if the source file exists
if ((test-path $sourceFile) -eq $false)
{
    logEntry 1 "Check Source File" $("File not found: " + $sourceFile)
    Exit
}


# Create a FTPWebRequest object to handle the connection to the ftp server
$ftpRequest = [System.Net.FtpWebRequest]::create($destination)

# set the request's network credentials for an authenticated connection
$ftpRequest.Credentials = New-Object System.Net.NetworkCredential($username,$password)
$ftpRequest.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$ftpRequest.UseBinary = $true
$ftpRequest.KeepAlive = $false

$succeeded = $true
$try = 1

do{
    trap [Exception]{
        $script:succeeded = $false
        logEntry 1 "Check FTP Connection" $_.Exception.Message
        $script:try++
        start-sleep -s $connectionTryInterval
        continue
        }
        $ftpResponse = $ftpRequest.GetResponse()

} while(($try -le $connectionTries) -and (-not $succeeded))

if ($succeeded) {
    logEntry 0 "Connection to FTP" "Success"


    # Open a filestream to the source file
    trap [Exception]{
        logEntry 1 "Check File Connection" $_.Exception.Message
        $sourceStream.Close()
        $ftpResponse.Close()
        exit
    }
    $sourceStream = New-Object IO.FileStream ($(New-Object System.IO.FileInfo $sourceFile),[IO.FileMode]::Open)
    [byte[]]$readbuffer = New-Object byte[] 1024

    logEntry 0 "Starting file transfer" "Success"
    # get the request stream, and write the bytes into it
    $rs = $ftpRequest.GetRequestStream()
    do{
        $readlength = $sourceStream.Read($readbuffer,0,1024)
        $rs.Write($readbuffer,0,$readlength)
    } while ($readlength -ne 0)

    logEntry 0 "Transfer complete" "Success"
    # be sure to clean up after ourselves
    $rs.Close()
    #$rs.Dispose()
    $sourceStream.Close()
    #$sourceStream.Dispose()

}
$ftpResponse.Close()

尝试在末尾捕获传输正常响应的示例:

logEntry 0 "Starting file transfer" "Success"
# get the request stream, and write the bytes into it
$rs = $ftpRequest.GetRequestStream()
do{
    $readlength = $sourceStream.Read($readbuffer,0,1024)
    $rs.Write($readbuffer,0,$readlength)
} while ($readlength -ne 0)
$rs.Close()
#start-sleep -s 2

trap [Exception]{
    $script:succeeded = $false
    logEntry 1 "Check FTP Connection" $_.Exception.Message
    continue
}
$ftpResponse = $ftpRequest.GetResponse()

与其使用Get Content将整个文件读取到内存中,不如尝试一次读取一个块并将其写入FTP请求流。我会使用较低级别的.NET文件流API来进行读取。诚然,您不会认为10MB会造成内存问题

此外,请确保在获取请求流并写入请求流后获得响应。响应流的获取是上载数据的方式。从文档:

当使用FtpWebRequest对象 将文件上载到服务器时,必须 将文件内容写入请求 通过调用 GetRequestStream方法或其 异步对等体 BeginGetRequestStream和 EndGetRequestStream方法。您必须 写入流并关闭 在发送请求之前进行流处理

请求通过发送到服务器 调用GetResponse方法或其 异步对等体 BeginGetResponse和EndGetResponse 方法。当请求的操作 完成后,将创建一个FtpWebResponse对象 返回。FtpWebResponse对象 提供操作的状态 以及从 服务器


与其使用Get Content将整个文件读取到内存中,不如尝试一次读取一个块并将其写入FTP请求流。我会使用较低级别的.NET文件流API来进行读取。诚然,您不会认为10MB会造成内存问题

此外,请确保在获取请求流并写入请求流后获得响应。响应流的获取是上载数据的方式。从文档:

当使用FtpWebRequest对象 将文件上载到服务器时,必须 将文件内容写入请求 通过调用 GetRequestStream方法或其 异步对等体 BeginGetRequestStream和 EndGetRequestStream方法。您必须 写入流并关闭 在发送请求之前进行流处理

请求通过发送到服务器 调用GetResponse方法或其 异步对等体 BeginGetResponse和EndGetResponse 方法。当请求的操作 完成后,将创建一个FtpWebResponse对象 返回。FtpWebResponse对象 提供操作的状态 以及从 服务器


我自己也遇到了一个类似的问题,RAM使用率影响了GB上传3MB文件,我发现:

 $content = gc -en byte $sourceFile
与:


提供更好的性能。正如其他地方提到的,对于真正大的文件,分块将是一个更好的解决方案,因为这样您就不会同时将整个文件保存在内存中,但上面的代码至少只消耗(文件大小)字节的RAM,这意味着它应该可以达到~10s MB的范围。

我自己也遇到了类似的问题,RAM使用量影响了GB上传3MB文件,我发现:

 $content = gc -en byte $sourceFile
与:


提供更好的性能。正如其他地方提到的,对于真正大的文件,分块将是一个更好的解决方案,因为这样您就不会同时将整个文件保存在内存中,但上面的代码至少只消耗(文件大小)字节的RAM,这意味着它应该可以达到~10s MB的范围。

以字节数组的形式读取它似乎是内存杀手。@keith hill谢谢。我做了很多环顾四周的工作,并如上所述修改了脚本。现在虽然当我第一次运行它时,它工作正常,但当我第二次运行它时,调用“GetResponse”时出现异常具有“0”参数的:“无法访问已释放的对象。每次交替运行时,都会出现错误。也许我不明白hwo-dispose实际上是如何工作的。我的.net有点欠缺。我不太了解您的代码,尤其是更新的部分以及它与代码其余部分的关系。在顶部的代码中,在将数据写入请求流之前,您似乎得到了响应(提交了数据)。如果我在重新运行之前留出5分钟时间,问题似乎就消失了。在发布一个完全更新的wierd字符串之前,我们正在处理一些wierd字符串连接问题$日志字符串=$(获取日期-格式“yyyy-MM-dd hh:MM:ss”)+“|”+($type)+“|”+($section)+“|”
 $content = [System.IO.File]::ReadAllBytes($sourceFile)