Microsoft.Office.Interop.Excel действительно медленно - PullRequest
40 голосов
/ 21 октября 2010

Я экспортирую матрицу 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");

Ответы [ 7 ]

64 голосов
/ 21 октября 2010

Вы обновляете отдельные ячейки. Это будет очень медленно. Если вы подумаете об этом, каждый раз, когда вы обновляете ячейку, вызов 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 x 800 x 2 = 1 920 000.

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

15 голосов
/ 21 октября 2010

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

8 голосов
/ 24 июня 2015

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

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

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

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

6 голосов
/ 10 июля 2015

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

2 голосов
/ 08 апреля 2016

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

Вы устанавливаете с помощью пакета Nu Get.https://www.nuget.org/packages/ClosedXML

2 голосов
/ 22 декабря 2010

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

0 голосов
/ 24 января 2017

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...