Преобразование XLS в PDF: индекс получения данных должен быть допустимым индексом в исключении поля во время GetBytes()

У меня есть приложение, которое конвертирует файлы в PDF. Сначала он сохраняет большой двоичный объект из MySQL во временный файл, а затем преобразует этот временный файл в PDF. Я получаю, что этот индекс данных должен быть допустимым индексом в ошибке исключения поля в GetBytes () только тогда, когда я пытаюсь преобразовать файл XLS. Другие типы файлов (BMP, XLSX, DOC, DOCX и т. д.) конвертируются.

private WriteBlobToTempFileResult WriteBlobToTempFile(int id, string fileType)
{
    Logger.Log(string.Format("Inside WriteBlobToTempFile() id: {0} fileType: {1}", id, fileType));
    WriteBlobToTempFileResult res = new WriteBlobToTempFileResult //return object
    {
        PrimaryKey = id
    }; 
    FileStream fs;                          // Writes the BLOB to a file 
    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.                        
    string connectionString = ConfigurationManager.AppSettings["MySQLConnectionString"]; //connection string from app.config
    string path = ConfigurationManager.AppSettings["fileDirectory"]; //get directory from App.Config
    
    try
    {
        MySqlConnection conn = new MySqlConnection(connectionString);
        conn.Open();
        //Determine records to convert, retrieve Primary Key and file type
        string sql = "SELECT FILE_DATA from " + TableName + " WHERE PK_TSP_DOCS_ID = @id";
        MySqlCommand cmd = new MySqlCommand(sql, conn);
        cmd.Parameters.AddWithValue("@id", id);
        MySqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess);                                                
        while (rdr.Read())
        {   
            // Create a file to hold the output.
            fs = new FileStream(path + @"\" + id + "." + fileType, FileMode.OpenOrCreate, FileAccess.Write);
            bw = new BinaryWriter(fs);

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

            // Read the bytes into outbyte[] and retain the number of bytes returned.
            retval = rdr.GetBytes(rdr.GetOrdinal("FILE_DATA"), 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;
                // *****IT FAILS AT THE LINE BELOW*****
                retval = rdr.GetBytes(rdr.GetOrdinal("FILE_DATA"), startIndex, outbyte, 0, bufferSize);
                // *****IT FAILS AT THE LINE ABOVE*****
            }
            // Write the remaining buffer.
            bw.Write(outbyte, 0, (int)retval);
            bw.Flush();

            // Close the output file.
            bw.Close();
            fs.Close();
        }
        // Close the reader and the connection.
        rdr.Close();
        conn.Close();
        res.FullPath = path + @"\" + id + "." + fileType;
    }
    catch (Exception ex)
    {
        res.Error = true;
        res.ErrorMessage = string.Format("Failed to write temporary file for record id: {0} of file type: {1}", id.ToString(), fileType);
        res.InternalErrorMessage = ex.Message; //string.Format("Caught Exception in WriteBlobToTempPDF(). Stack Trace: {0}", ex.StackTrace);
    }                                    
    return res;
}

person E. Choi    schedule 02.10.2020    source источник
comment
Мне просто интересно, проблема в том, что Lenght == N * bufferSize... тогда N * bufferSize начальный индекс недействителен...   -  person Selvin    schedule 02.10.2020
comment
используйте var length = rdr.GetBytes(index, 0, null, 0,0);, чтобы получить длину... затем добавьте startIndex < length в то время как   -  person Selvin    schedule 02.10.2020
comment
комментарий не по теме: размер буфера должен быть больше ... используйте 4 КБ, так как 100 Б очень мало   -  person Selvin    schedule 02.10.2020
comment
@Selvin Изменение размера буфера со 100 до 4000 помогло. Мне все еще нужно добавить код выше?   -  person E. Choi    schedule 02.10.2020
comment
Изменение размера буфера со 100 до 4000 сделало свое дело. Нет... этого недостаточно... теперь у вас будут проблемы, когда file length % 4000 == 0 используйте код из 2-го комментария... Что делать? все еще нужно добавить приведенный выше код? YES   -  person Selvin    schedule 02.10.2020
comment
@Selvin Где именно мне поставить var length = rdr.GetBytes(index, 0, null, 0,0); и startIndex < length?   -  person E. Choi    schedule 02.10.2020
comment
var length... перед while ... и измените while на while(retval == bufferSize && startIndex < length) Я не уверен ... но думаю, что даже while(startIndex < length) должен делать это ... да, вы также можете добавить var index = rdr.GetOrdinal("FILE_DATA"); и использовать его вместо вызова rdr.GetOrdinal("FILE_DATA") несколько раз   -  person Selvin    schedule 02.10.2020
comment
@Selvin Большое спасибо за вашу помощь!   -  person E. Choi    schedule 02.10.2020


Ответы (1)


Это ошибка в Oracle MySQL Connector/NET. Вы можете увидеть в https://mysql-net.github.io/AdoNetResults/#GetBytes_reads_nothing_at_end_of_buffer, что MySql.Data выдает IndexOutOfRangeException при попытке прочитать 0 байтов в конце буфера, но ни один другой поставщик ADO.NET этого не делает.

Вам следует переключиться на MySqlConnector (отказ от ответственности: я участник) и использовать MySqlDataReader.GetStream() и Stream.CopyTo для упрощения кода:

MySqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess);                                                
while (rdr.Read())
{   
    // Create a file to hold the output.
    using (var fs = new FileStream(path + @"\" + id + "." + fileType, FileMode.OpenOrCreate, FileAccess.Write))
    {
        // Open a Stream from the data reader
        using (var stream = rdr.GetStream(rdr.GetOrdinal("FILE_DATA"))
        {
            // Copy the data
            stream.CopyTo(fs);
        }
    }
}
person Bradley Grainger    schedule 02.10.2020