如何使用SqlDataReader重新填充字节数组?

时间:2012-02-01 19:31:06

标签: c# asp.net bytearray enterprise-library out-of-memory

这是参考:byte[] and efficiently passing by reference

此帖中的SqlDataReaderGetting binary data using SqlDataReader

在循环中,我正在调用数据库并返回一个大对象(varbinary[max])。目前,我遇到了OutOfMemory例外,因此我正在尝试减少大对象堆(LOH)中的占用空间。

所以,我正在为我下载的最大文件创建一个字节数组,并添加一些填充以防万一。例如:

byte[] currentFile = new byte[largestFileSize * 1.1];

然后我传递了这个currentFile数据库方法。目前,我们使用EnterpriseLibrary访问数据库:

DbCommand storedProcedure = MedicareDatabase.Db.GetStoredProcCommand(spName);

storedProcedure.CommandTimeout = 5000;

if (parameters != null)
{
    foreach (Param parameter in parameters)
    {
        if (parameter != null)
        {
            MedicareDatabase.Db.AddInParameter(storedProcedure, parameter.ParameterName, parameter.DbType, parameter.Value);
        }
    }
}

try
{
    BinaryWriter bw;                        // Streams the BLOB to the FileStream object.

    int bufferSize = 100;                   // Size of the BLOB buffer.
    byte[] outbyte = new byte[bufferSize];  // The BLOB byte[] buffer to be filled by GetBytes.
    long retval;                            // The bytes returned from GetBytes.
    long startIndex = 0;                    // The starting position in the BLOB output.

    var myReader = MedicareDatabase.Db.ExecuteReader(storedProcedure);

    while (myReader.Read())
    {
        bw = new BinaryWriter();

        // Reset the starting byte for the new BLOB.
        startIndex = 0;

        // Read the bytes into outbyte[] and retain the number of bytes returned.
        retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize);

        // Continue reading and writing while there are bytes beyond the size of the buffer.
        while (retval == bufferSize)
        {
            bw.Write(outbyte);
            bw.Flush();

            // Reposition the start index to the end of the last buffer and fill the buffer.
            startIndex += bufferSize;
            retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize);
        }

        // Write the remaining buffer.
        bw.Write(outbyte, 0, (int)retval - 1);
        bw.Flush();

        // Close the output file.
        bw.Close();
    }

这是对上面第二篇文章中列出的代码的修改。

以下是我的问题(如果我应该提出不同的问题,请随时纠正我)

  1. 如何在不创建新对象的情况下有效地重新填充byte[]

  2. 上面的代码不使用创建新对象所需的CommandBehavior.SequentialAccess。如何将EnterpriseLibraryCommandBehavior s一起使用?

  3. 我正在调用数据库并返回byte[]数组

    更新

    所以过了一段时间,我决定手动填充字节数组。该引用现已成功通过。

            SqlConnection pubsConn = null;
            SqlCommand logoCMD = null;
            SqlDataReader myReader = null;
    
            try
            {
                pubsConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MedicareAccess"].ConnectionString);
                logoCMD = new SqlCommand("esMD.proc_WS_SelectBiztalkBinary", pubsConn);
                logoCMD.CommandType = CommandType.StoredProcedure;
    
                SqlParameter submissionSetParamter = logoCMD.Parameters.Add("@submissionSetId", SqlDbType.UniqueIdentifier);
                submissionSetParamter.Value = currentDocument.SubmissionSetId;
    
                SqlParameter fileNameParam = logoCMD.Parameters.Add("@fileName", SqlDbType.VarChar, 100);
                fileNameParam.Value = currentDocument.FullFileName;
    
    
                int bufferSize = 100;                   // Size of the BLOB buffer.
                byte[] outbyte = new byte[bufferSize];  // The BLOB byte[] buffer to be filled by GetBytes.
                long retval;                            // The bytes returned from GetBytes.
                long startIndex = 0;                    // The starting position in the BLOB output.
    
                // Open the connection and read data into the DataReader.
                pubsConn.Open();
                myReader = logoCMD.ExecuteReader(CommandBehavior.SequentialAccess);
    
                Array.Clear(data, 0, data.Length);
    
                if (myReader == null)
                {
                    return;
                }
    
                while (myReader.Read())
                {
                    currentDocument.Size = (int)myReader.GetBytes(0, 0, null, 0, 0);
                    int locationCounter = 0;
                    // Reset the starting byte for the new BLOB.
                    startIndex = 0;
    
                    // Read the bytes into outbyte[] and retain the number of bytes returned.
                    retval = myReader.GetBytes(0, startIndex, outbyte, 0, bufferSize);
    
                    // Continue reading and writing while there are bytes beyond the size of the buffer.
                    while (retval == bufferSize)
                    {
                        for (int i = 0; i < retval; i++)
                        {
                            data[locationCounter] = outbyte[i];
                            locationCounter++;
                        }
    
                        // Reposition the start index to the end of the last buffer and fill the buffer.
                        startIndex += bufferSize;
                        retval = myReader.GetBytes(0, startIndex, outbyte, 0, bufferSize);
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (myReader != null)
                {
                    myReader.Dispose();
                    myReader.Close();
                    myReader = null;
                }
    
                if (pubsConn != null)
                {
                    pubsConn.Dispose();
                    pubsConn.Close();
                    pubsConn = null;
                }
            }
    

    我确信有更有效的方式来写这个。并没有经过全面测试。但参考文献终于有效了。

1 个答案:

答案 0 :(得分:0)

所以我用以下代码替换了主循环:

            if (myReader.Read())
            {
                currentDocument.Size = myReader.GetBytes(0, 0, null, 0, 0);

                // Reset the starting byte for the new BLOB.
                long startIndex = 0;
                int bufferSize = 8196;                   // Size of the BLOB buffer.
                byte[] outbyte = new byte[bufferSize];  // The BLOB byte[] buffer to be filled by GetBytes.
                long bytesInBuffer = 0;                            // The bytes returned from GetBytes.

                // Continue reading and writing while there are bytes beyond the size of the buffer.
                while (startIndex < currentDocument.Size)
                {
                    bytesInBuffer = myReader.GetBytes(0, startIndex, outbyte, 0, bufferSize);
                    Array.Copy(outbyte, 0, currentDocument.Data, startIndex, bytesInBuffer);
                    startIndex += bytesInBuffer;
                }
            }

立即行动。