You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell调用SQL存储过程获取大于2GB varbinary(max)文件无返回问题

问题根因

你的判断是准确的,问题出自[system.data.SqlDbType]::varbinary,-1作为输出参数的限制:System.Data.SqlClient组件对存储过程输出参数的varbinary(max)类型有硬编码的2GB大小上限,超过阈值的数据会被静默丢弃,不会触发报错,这就是2GB以上文件无返回的核心原因。
同时你当前的用法也浪费了Filestream的流式读写优势,将整个大文件一次性加载到内存中,既容易触发大小限制,也会带来极高的内存占用。

解决方案:改为流式读取(推荐,无大小限制)

放弃用存储过程输出参数返回二进制内容,改为直接查询返回行,通过SqlDataReader的流接口读取文件,支持任意大小的Filestream文件,内存占用极低。

1. 修改存储过程

去掉@ZIPFile输出参数,直接返回查询结果:

create PROCEDURE [my].[getZIPFile]  (
@checkSum varchar(100) OUTPUT,
@aktScriptVersion decimal(4,2) output
) 
AS 
BEGIN
IF ..... = 'SQLBinary'
    BEGIN
        -- 直接返回二进制列,不再赋值给输出参数
        SELECT [DataFile]
        FROM [deployment].[softwarerepository]
        -- 同时给输出参数赋值
        SELECT @checkSum = [checksum], @aktScriptVersion = version_nr
        FROM [deployment].[softwarerepository]
    END
END

2. 修改PowerShell函数

改用ExecuteReader读取流,直接写入本地文件(也可根据需求写入内存流,大文件推荐直接落盘):

Function Get-ZIPFile
{
    param(
    $outputPath, # 新增参数:ZIP文件输出路径
    .... 其他原有参数
    )

    $conn = New-Object System.Data.SqlClient.SqlConnection
    # 连接字符串增加MultipleActiveResultSets=True支持同时读取输出参数和结果集
    $conn.ConnectionString = "Server=myServer;Database=myDB;Integrated Security=no;User=SQL_user;Password=xxxxx;MultipleActiveResultSets=True"
    $conn.Open() | out-null
    $cmd = new-Object System.Data.SqlClient.SqlCommand 
    $cmd.Connection = $conn
    $cmd.CommandType = [System.Data.CommandType]::StoredProcedure
    $cmd.CommandText = "deployment.getZIPFile"
    #### 移除@ZIPFile输出参数配置
    $cmd.Parameters.Add("@checkSum",[system.data.SqlDbType]::Varchar,100) | out-Null
    $cmd.Parameters['@checkSum'].Direction = [system.data.ParameterDirection]::Output
    $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

    # 改用Reader读取结果集
    $reader = $cmd.ExecuteReader()
    $ausgabe = [pscustomobject]@{
        zipFileSavePath = $outputPath
        checkSum = ""
        aktScriptVersion = 0
    }
    if($reader.HasRows)
    {
        $reader.Read()
        # 获取二进制列的流,分段写入文件避免内存溢出
        $stream = $reader.GetStream(0)
        $fileStream = New-Object System.IO.FileStream($outputPath, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write)
        $buffer = New-Object byte[] 8192
        $readCount = 0
        while(($readCount = $stream.Read($buffer, 0, $buffer.Length)) -gt 0)
        {
            $fileStream.Write($buffer, 0, $readCount)
        }
        $fileStream.Flush()
        $fileStream.Close()
        $stream.Close()
    }
    $reader.Close()
    # 读取输出参数
    $ausgabe.checkSum = $cmd.Parameters["@checkSum"].Value
    $ausgabe.aktScriptVersion = $cmd.Parameters["@aktScriptVersion"].Value

    $cmd.Dispose()            
    $conn.Close() 
    $conn.Dispose()
    return $ausgabe
}
可选方案:直接读取Filestream路径(适合超大型文件)

如果文件普遍超过10GB,还可以直接查询Filestream的文件路径和事务上下文,通过Win32 API直接读取Filestream的物理文件,性能更高,需要在存储过程中返回DataFile.PathName()和GET_FILESTREAM_TRANSACTION_CONTEXT(),PowerShell侧调用System.Data.SqlTypes.SqlFileStream读取即可。

内容的提问来源于stack exchange,提问作者Purclot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 14:48:05