it-swarm.com.ru

Microsoft.Office.Interop.Excel действительно медленно

Я экспортирую матрицу 1200 X 800 (indexMatrix) в файл Excel, используя стандартный файл Microsoft.Office.Interop.Excel. Приложение работает, просто оно действительно очень медленное (даже для матрицы 100 x 100). Я также экспортирую в текстовый файл через TextWriter, и он работает почти мгновенно. Есть ли способ быстрее экспортировать в файл Excel? 

Вот мой код:

        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");
38
Alex

Вы обновляете отдельные ячейки. Это будет очень медленно. Если вы подумаете об этом, каждый раз, когда вы обновляете ячейку, вызов RPC будет перенаправляться в процесс Excel.

Это будет намного быстрее, если вы назначите двумерный массив значений в диапазон Excel с одинаковыми измерениями в одном операторе (один межпроцессный вызов) вместо текущих 1200 x 800 = 960 000 межпроцессных вызовов. ,.

Что-то вроде:

// 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);

На самом деле, чтобы быть педантичным, в приведенном выше коде есть три межпроцессных вызова (.Cells, .get_Resize и .set_Value), и в вашем коде есть два вызова на итерацию (.Cells get и неявный .set_Value) для всего 1200 х 800 х 2 = 1 920 000.

Примечание range.get_Resize и range.set_Value были необходимы для старой версии библиотеки взаимодействия Excel, которую я использовал, когда этот пост был впервые создан. В эти дни вы можете использовать range.Resize и range.Value, как отмечено в комментарии @ The1nk.

62
Joe

Взаимодействие с Excel никогда не будет быстрым. Вы в основном управляете экземпляром приложения Excel. Вы можете добиться большего успеха, создав файл CSV, а затем с помощью взаимодействия Excel преобразовать его в файл .xls или .xlsx.

15
Yuliy

У меня были похожие проблемы при чтении очень большого файла Excel, и это заняло более 2 часов с помощью взаимодействия.

Я попытался использовать ClosedXml, и процесс занял менее 10 секунд . ClosedXml

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

Также имейте в виду, что взаимодействие не будет работать на вашем сервере, если у вас не установлен Excel. ClosedXml не требует установки Excel.

8
MIKE

Отключите ScreenUpdating перед записью каких-либо данных, затем Application.ScreenUpdating = FALSE включите в конце кода = TRUE

5
Paul Roberts

Используйте Value2, чтобы сделать это быстро; Показать Excel перед заполнением данных

2
Siarhei Kuchuk

ClosedXML - это чудо, намного быстрее и проще в использовании. 

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

Вы устанавливаете, используя новый пакет Get. https://www.nuget.org/packages/ClosedXML

2
Chong Ching

Есть три способа сделать это, 2 из которых упомянуты в разных ответах другими:

  1. Непосредственно установите значение диапазона в Excel для 2D-массива.
  2. Запишите данные в файл CSV, затем используйте interop для сохранения файла CSV в виде файла xls или xlsx.
  3. Запишите данные в файл CSV, затем используйте функцию подключения к данным, чтобы использовать CSV в качестве источника данных и импортировать данные.

Все три метода, описанные выше, очень быстрые. Я мог бы записать данные размером 90000 строк и 100 столбцов примерно за 6 секунд.

Постскриптум Однако они не решили мою проблему с форматированием данных для границ, стилей шрифтов, цветов, объединения ячеек и т.д.

0
Sanjit