2010-10-21 25 views
30

Estoy exportando una matriz de 1200 X 800 (matriz de índices) a un archivo de Excel utilizando el estándar Microsoft.Office.Interop.Excel. La aplicación funciona, solo que es realmente muy lenta (incluso para la matriz de 100 x 100). También exporto en un archivo de texto a través de un TextWriter y funciona casi al instante. ¿Hay alguna manera de exportar al archivo Excel más rápido?Microsoft.Office.Interop.Excel realmente lento

Aquí está mi código:

 Excel.Application xlApp=new Excel.Application(); 
     Excel.Workbook xlWorkBook; 
     Excel.Worksheet xlWorkSheet; 
     object misValue = System.Reflection.Missing.Value; 

     //xlApp = new Excel.ApplicationClass(); 
     xlWorkBook = xlApp.Workbooks.Add(misValue); 

     xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1); 
     for (int i = 0; i < 800; i++) //h 
      for (int j = 0; j < 1200; j++) 
       xlWorkSheet.Cells[i+1,j+1] =indexMatrix[i][j]; 


     xlWorkBook.SaveAs("C:\\a.xls", Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue); 
     xlWorkBook.Close(true, misValue, misValue); 
     xlApp.Quit(); 

     releaseObject(xlWorkSheet); 
     releaseObject(xlWorkBook); 
     releaseObject(xlApp); 

     MessageBox.Show("Excel file created , you can find the file c:\\csharp-Excel.xls"); 

Respuesta

49

Está actualizando celdas individuales. Eso va a ser muy lento. Si lo piensa, cada vez que actualice una celda, se organizará una llamada RPC al proceso de Excel.

Será mucho más rápido si asigna su matriz bidimensional de valores para un rango de Excel de las mismas dimensiones en un solo estado (llamada de un proceso de cruz) en lugar de su actual 1200 x 800 = 960.000 cruzada procesar llamadas

Algo así como:

// Get dimensions of the 2-d array 
int rowCount = indexMatrix.GetLength(0); 
int columnCount = indexMatrix.GetLength(1); 
// Get an Excel Range of the same dimensions 
Excel.Range range = (Excel.Range) xlWorkSheet.Cells[1,1]; 
range = range.get_Resize(rowCount, columnCount); 
// Assign the 2-d array to the Excel Range 
range.set_Value(Excel.XlRangeValueDataType.xlRangeValueDefault, indexMatrix); 

realidad, para ser pedante, hay tres procesos cruzados llama en el código anterior (.Cells, .get_Resize y .set_Value), y hay dos llamadas por iteración en su código (.Cells get y un .set_Value implícito) para un total de 1200 x 800 x 2 = 1,920,000.

Nota range.get_Resize y range.set_Value se necesitaban para una versión antigua de la biblioteca de interoperabilidad de Excel que estaba usando cuando este post fue escrito por primera vez. Estos días puede usar range.Resize y range.Value como se indica en el comentario de @ The1nk.

+0

parece haber un problema en .get_Resize. Parece que no existe. – Alex

+0

en la línea excel.range, aparece el siguiente error '' System .__ ComObject 'no contiene una definición para' get_Resize '' – Alex

+0

Creo que la edición lo arreglará. Las celdas [1,1] no devuelven un objeto Range, por lo que deben emitirse. – Joe

13

interoperabilidad de Excel nunca va a ser rápido. Básicamente, controlas remotamente una instancia de la aplicación de Excel. Puede tener más éxito al crear un archivo CSV y luego usar la interoperación de Excel para convertir esto a un archivo .xls o .xlsx

+1

+1 Bonito enfoque, y esto asegura que será más rápido también, ya que un archivo CSV es más un texto archivo, para que la clase 'TextWriter' pueda manejarlo. –

+0

Sí, ese es mi método preferido también. Aunque te encuentras con problemas cuando los valores de celda contienen líneas nuevas, ya que eso arruina tu índice de fila. ¿Alguien tiene algún consejo para este problema? – Yevgeniy

+1

En respuesta a mi comentario anterior: use import-csv (powershell) o una función de biblioteca equivalente que manejará las situaciones desordenadas con calificadores de calificación y líneas nuevas usadas en los valores de campo. – Yevgeniy

2

Use Value2 para hacerlo rápido; Mostrar excel antes de completar los datos

6

Tuve problemas similares al leer un archivo de Excel extremadamente grande y me tomó más de 2 horas usando interoperabilidad.

Intenté usar ClosedXml y el proceso tomó menos de 10 segundos. ClosedXml

// To loop 
Sheet.Row(y).Cell(x).Value 

También hay que tener en cuenta la interoperabilidad no va a funcionar en su servidor a menos que haya instalado Excel. ClosedXml no necesita Excel instalado.

+0

Primera vez que usas ClosedXML y es REALMENTE rápido. Usé InsertData con una matriz de matrices y un argumento. Muy suave en comparación con la locura HSSF y HSSF de POI y las excepciones COM de interoperabilidad !!! +1 – Mzn

2

Desactivar ScreenUpdating antes de escribir cualquier dato, Application.ScreenUpdating = FALSE después enciende al final del código = TRUE

2

ClosedXML es un milagro, es mucho más rápido y más fácil de usar.

var workbook = new XLWorkbook();//create the new book 

var worksheet = workbook.Worksheets.Add("Computer Install");// Add a sheet 
worksheet.Cell(1,1).Value = "PC Name";// (Row, column) write to a cell 

workbook.SaveAs(@"LIC documents.xlsx");// Save the book 

Se instala utilizando un paquete Nu Get. https://www.nuget.org/packages/ClosedXML

+0

Sí, es impresionante. Pasó de aproximadamente 4.5 horas a 5 minutos. Github: https://github.com/closedxml/closedxml – Andres

0

Hay tres maneras de hacer esto, 2 de los cuales se mencionan en diferentes respuestas por otros:

  1. establecer directamente el valor de un rango en Excel a la matriz 2D.
  2. Escriba datos en un archivo CSV, luego use interopera para guardar el archivo CSV como un archivo xls o xlsx.
  3. Escriba datos en un archivo CSV, luego use la función de conexiones de datos para usar el CSV como fuente de datos e importar los datos.

Todos los tres métodos anteriores son muy rápidos. Podría escribir datos con un tamaño de 90000 filas y 100 columnas en alrededor de 6 segundos.

P.S. Sin embargo, no resolvió mi problema con el formato de los datos para bordes, estilos de fuente, colores, fusión de celdas, etc.

Cuestiones relacionadas