问题描述
我正在尝试从 sql Server 导入 ZIP 文件。 sql 表中的列定义为 varbinary(max)。我正在使用带有输出参数的 sql 存储过程,该过程为我提供了这个 zip 文件。 我定义了(见代码)一个 cmd.parameter (system.data.sqldbtype::varbinary,-1) ,“-1”应该是“max”-length,但我没有得到任何记录($rd.HasRecords为空..).
感谢您的帮助。
Function Get-sqlData
{
$conn = New-Object System.Data.sqlClient.sqlConnection
$conn.ConnectionString = "Server=XXXX\YYYY;Database=sql_XXX;Integrated Security=no;User=sqlServer_XX;Password=xxYYYY"
$conn.open() | out-null
$cmd = new-Object System.Data.sqlClient.sqlCommand #("deployment.getZIPFile",$conn)
#Proz
$cmd.Connection = $conn
$cmd.CommandType = [System.Data.CommandType]::StoredProcedure
$cmd.CommandText = "deployment.getZIPFile"
#### Proz-Parameter
$cmd.Parameters.Add("@file_typ",[system.data.sqlDbType]::VarChar,5) | out-Null
$cmd.Parameters['@file_typ'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@file_typ'].value = 'PS'
#
$cmd.Parameters.Add("@domain",5) | out-Null
$cmd.Parameters['@domain'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@domain'].value = ($env:USERDNSDOMAIN).Split('.')[0] # domain
#
$cmd.Parameters.Add("@serverName",50) | out-Null
$cmd.Parameters['@serverName'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@serverName'].value = $env:COmpuTERNAME #local server
#
$cmd.Parameters.Add("@scriptVersion",[system.data.sqlDbType]::decimal) | out-Null
$cmd.Parameters['@scriptVersion'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@ScriptVersion'].Precision=18
$cmd.Parameters['@ScriptVersion'].Scale=2
$cmd.Parameters['@scriptVersion'].value = $MyVersion
#
$cmd.Parameters.Add("@operatingSystem",100) | out-Null
$cmd.Parameters['@operatingSystem'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@operatingSystem'].value = (gwmi -Class win32_operatingsystem).caption
#
$cmd.Parameters.Add("@serverTyp",50) | out-Null
$cmd.Parameters['@serverTyp'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@serverTyp'].value = $serverTyp
#
$cmd.Parameters.Add("@serverSubTyp",50) | out-Null
$cmd.Parameters['@serverSubTyp'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['@serverSubTyp'].value = $serverSubTyp
#
$cmd.Parameters.Add("@aktScriptVersion",[system.data.sqlDbType]::decimal) | out-Null
$cmd.Parameters['@aktScriptVersion'].Direction = [system.data.ParameterDirection]::Output
$cmd.Parameters['@aktScriptVersion'].Precision=18
$cmd.Parameters['@aktScriptVersion'].Scale=2
#
$cmd.Parameters.Add("@ZIPFile",[system.data.sqlDbType]::varbinary,-1) | out-Null
$cmd.Parameters['@ZIPFile'].Direction = [system.data.ParameterDirection]::Output
#### Proz-Parameter Ende
#$cmd.ExecuteNonQuery() #| out-null ## org
$rd = $cmd.ExecuteReader() # gibt es Records?
#$rd = $cmd.ExecuteNonQuery()
if ($rd.HasRows) # gibt es Records?
{
$bufferSize = 8192
# Stream Lesen..
# Create a byte array for the stream.
$out = [array]::CreateInstance('Byte',$bufferSize)
# Looping through records
While ($rd.Read())
{
$fileLocation = "C:\PerfLogs\XXXX\ZIPImport.7z"
#Write-Output ("Exporting: {0}" -f $rd.GetInt32(0));
# New BinaryWriter
$fs = New-Object System.IO.FileStream $fileLocation,'Create','Write';
$bw = New-Object System.IO.BinaryWriter $fs;
$start = 0;
# Read first byte stream
$received = $rd.GetBytes(0,$start,$out,$bufferSize - 1); ## 1
While ($received -gt 0)
{
$bw.Write($out,$received);
$bw.Flush();
$start += $received;
# Read next byte stream
$received = $rd.GetBytes(0,$bufferSize - 1); ## 1
}
$bw.Close();
$fs.Close();
}
# Closing & disposing all objects
$fs.dispose()
$rd.Close()
$cmd.dispose()
$conn.Close()
Write-Output ("ZIP-Import Finished")
# 7z Sektion
$unzip = 'C:\PerfLogs\xxxx\Modul'
& ${env:ProgramFiles}\7-Zip\7z.exe x $fileLocation "-o$($unzip)" -y
Write-Output ("UNZIP Finished")
}
$conn.Close()
$conn.dispose()
}
}
解决方法
正如解决您问题的评论中所述,您问题中的参数是正确的。问题在于执行过程和处理结果的代码。
此处无需使用 SqlDataReader
,因为 proc 在输出参数中而不是在结果集列中返回值。此外,由于返回的是整个字节数组,因此将值直接写入文件比在读/写循环中更容易。
以下是将输出参数字节数组写入文件的一种方法。
# execute the proc,returning the @ZIPFile output parameter
$cmd.ExecuteNonQuery() | out-null
if($cmd.Parameters["@ZIPFile"].Value -eq [System.DBNull]::Value) {
Write-Output "Zipfile not found in database"
}
else {
# write the byte arrary output value to a file
$fileLocation = "C:\PerfLogs\XXXX\ZIPImport.7z"
Write-Output "Exporting $($cmd.Parameters["@ZIPFile"].Value.Length) bytes to $fileLocation"
[System.IO.File]::WriteAllBytes($fileLocation,$cmd.Parameters["@ZIPFile"].Value)
}