none
Exportar DataTable a Excel con uso de Microsoft.Office.Interop.Excel o sin este pero que sea un proceso rápido con gran cantidad de registros. RRS feed

  • Pregunta

  • Hola buen día

    Primeramente tengo el siguiente método haciendo uso de Microsoft.Office.Interop.Excel para exportal el DataTable a Excel

    string ruta = "C:\\Users\\NewUsers\\Documents\\Excel.xls"

    public void ExportarExcel(DataTable oDataTable, string ruta)
            {
                if ((oDataTable == null) || (String.IsNullOrEmpty(ruta)))
                {
                    throw new ArgumentNullException();
                }

                Microsoft.Office.Interop.Excel.Application excel = null;
                Microsoft.Office.Interop.Excel.Workbook book = null;

                try
                {
                    excel = new Microsoft.Office.Interop.Excel.Application();

                    if (!File.Exists(ruta))
                    {
                        book = excel.Workbooks.Add();
                        book.SaveAs(ruta);
                        book.Close();
                        excel.Quit();
                    }

                    // Abrimos el libro de trabajo.
                    book = excel.Workbooks.Open(ruta);

                    int indiceColumna = 0;

                    foreach (DataColumn col in oDataTable.Columns)  //Columnas
                    {
                        indiceColumna++;
                        excel.Cells[1, indiceColumna] = col.ColumnName;
                    }

                    int indiceFila = 0;

                    foreach (DataRow row in oDataTable.Rows)  //Filas
                    {
                        indiceFila++;

                        indiceColumna = 0;

                        foreach (DataColumn col in oDataTable.Columns)  //Columnas
                        {
                            indiceColumna++;
                            excel.Cells[indiceFila + 1, indiceColumna] = row[col.ColumnName];
                        }
                        excel.Columns.AutoFit();
                    }

                    //excel.Visible = true;
                }
                catch (Exception ex)
                {
                    if (book != null)
                    {
                        book.Saved = true;
                    }

                    throw new Exception(ex.Message);
                }
                finally
                {
                    if (book != null)
                    {
                        if (!book.Saved)
                        {
                            book.Save();
                        }
                        book.Close();
                    }
                    book = null;

                    if (excel != null)
                    {
                        // Si procede, cerramos Excel y disminuimos el recuento de referencias al objeto Excel.Application.
                        excel.Quit();

                        while (System.Runtime.InteropServices.Marshal.ReleaseComObject(excel) > 0)
                        {

                        }
                    }
                    excel = null;
                }
            }

    Si el archivo Excel no existe en la ruta que especifico se creara de resto lo abrirá y sobrescribirá los datos en este. Con pequeños registros funciona lo mas de normal y sale rápido el reporte….pero al hacerlo con 2000 mil registros tarda unos 40 segundos en generarme el archivo…….y pues es demasiado tiempo………Necesito generar reportes con mas de 20.000 o 40.000 registros, pueden ser más o menos  pero aun así necesito que este proceso no demore demasiado. No sé si alguno conozca una manera de hacer más eficiente el método que he puesto o realizarlo de otra manera así no haga uso de las extensiones de Interop para general el Excel.

    Otro método que tengo es el siguiente:

    public void ExportToXls(DataTable table, string ruta)
            {
                try
                {

                    HttpContext context = HttpContext.Current;
                    table.WriteXml(ruta);
                    context.Response.Clear();
                    context.Response.ClearContent();
                    context.Response.ClearHeaders();
                    context.Response.ContentType = "application/octet-stream";
                    context.Response.AddHeader("Content-Disposition", "attachment; filename=\""+ruta+"");
                    context.Response.WriteFile(ruta);
                    context.Response.Flush();
                    context.Response.Close();
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message + "error al generar el xls");
                }
            }

    Pero al momento que llega al table.WriteXml(ruta); dice que el DataTable no se ha serializado o que el DataTable no contiene un nombre especificado.

    Estoy atento a cualquier ayuda, mil gracias.


    sábado, 9 de diciembre de 2017 15:53

Respuestas

  • No sé si alguno conozca una manera de hacer más eficiente el método que he puesto

    La razón por la que es lento el método que has puesto es porque tiene que hacer una llamada a través de COM/Interop por cada celda que traspasas. Si multiplicas el número de filas por el número de columnas, verás que te sale un número muy grande de llamadas.

    El remedio para acelerarlo, si quieres seguir usando COM/Interop, es meter todos los datos (todas las filas con todas sus columnas) en un array y pasar el array de golpe a Excel en una sola llamada. No me sé de memoria cuál es la instrucción de Excel que recibe el Array (igual que ahora llamas a excel.Cells=valor), pero no te debería resultar difícil encontrarla haciendo una búsqueda en la red.

    Otra alternativa que es también rápida es usar el driver de OleDb. Ahí le insertas las filas con una instrucción INSERT, igual que si las estuvieses grabando en base de datos en lugar de grabarlas en Excel, y es un proceso bastante rápido. La principal pega que tiene es que necesitas que esté de antemano instalado el driver de OleDb para Excel en la máquina de destino, y que hay que tener la precaución de que es un driver distinto según que tu programa se ejecute en 32 o en 64 bits.

    La alternativa final que te sugiero es usar alguna librería para grabar directamente el fichero .xlsx, como por ejemplo Microsoft OpenXML (descarga gratuita). La principal pega es que la curva de aprendizaje es muy empinada, pero una vez que hayas aprendido a usar esta librería tiene la ventaja de que es potentísima (puedes hacer de todo con los ficheros de Excel), que es muy rápida si se usa correctamente, y que funciona incluso aunque no tengas Excel instalado.

    sábado, 9 de diciembre de 2017 16:10
    Moderador