简体   繁体   English

Microsoft.Office.Interop.Excel 真的很慢

[英]Microsoft.Office.Interop.Excel really slow

I am exporting a 1200 X 800 matrix (indexMatrix) to a excel file using the standard Microsoft.Office.Interop.Excel.我正在使用标准 Microsoft.Office.Interop.Excel 将 1200 X 800 矩阵 (indexMatrix) 导出到 excel 文件。 The app works, just that it is really really really slow( even for the 100 x 100 matrix) .该应用程序有效,只是它真的真的很慢(即使对于 100 x 100 矩阵)。 I also export in a text file through a TextWriter an it works almost instantly .我还通过 TextWriter 导出一个文本文件,它几乎可以立即工作。 Is there any way to export to the excel file faster?有什么办法可以更快地导出到excel文件?

Here is my code :这是我的代码:

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

You are updating individual cells.您正在更新单个单元格。 That's going to be very slow.这将非常缓慢。 If you think about it, each time you update a cell, an RPC call will be marshalled to the Excel process.如果您考虑一下,每次更新单元格时,都会将 RPC 调用编组到 Excel 进程。

It will be much faster if you assign your two dimensional array of values to an Excel Range of the same dimensions in a single statement (one cross-process call) instead of your current 1200 x 800 = 960,000 cross-process calls.如果你在一条语句(一个跨进程调用),代替目前的1200 * 800 = 960000跨进程调用指定您的值二维数组相同尺寸的Excel范围将会快很多

Something like:类似的东西:

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

Actually, to be pedantic, there are three cross-process calls in the above code (.Cells, .get_Resize and .set_Value), and there are two calls per iteration in your code (.Cells get and an implicit .set_Value) for a total of 1200 x 800 x 2 = 1,920,000.实际上,为了迂腐,上面的代码中有三个跨进程调用(.Cells、.get_Resize 和 .set_Value),并且在你的代码中每次迭代有两个调用(.Cells get 和一个隐式的 .set_Value)总共 1200 x 800 x 2 = 1,920,000。

Note range.get_Resize and range.set_Value were needed for an old version of the Excel interop library I was using when this post was first authored.注意range.get_Resizerange.set_Value是我第一次创作这篇文章时使用的旧版 Excel 互操作库所需要的。 These days you can use range.Resize and range.Value as noted in the comment by @The1nk.这些天你可以使用range.Resizerange.Value如@The1nk 的评论中所述。

Excel interop is never going to be fast. Excel 互操作永远不会很快。 You're basically remote-controlling an instance of the Excel application.您基本上是在远程控制 Excel 应用程序的一个实例。 You might have more success by creating a CSV file and then using Excel interop to convert this to a .xls or .xlsx file通过创建 CSV 文件,然后使用 Excel 互操作将其转换为 .xls 或 .xlsx 文件,您可能会取得更大的成功

I had similar problems when reading an extremely large excel file and it took over 2 hours using interop.我在读取一个非常大的 excel 文件时遇到了类似的问题,使用互操作需要 2 个多小时。

I tried using ClosedXml and the process took less than 10 seconds.我尝试使用 ClosedXml,该过程不到 10 秒。 ClosedXml关闭的Xml

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

Also keep in mind interop will not work on your server unless you have excel installed.另外请记住,除非您安装了 excel,否则互操作将无法在您的服务器上运行。 ClosedXml does not need excel installed. ClosedXml 不需要安装 excel。

在写入任何数据之前关闭ScreenUpdatingApplication.ScreenUpdating = FALSE然后在代码结束时打开= TRUE

ClosedXML is a miracle, it's a great deal faster and easier to use. 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

You install using a nu Get package.您使用 nu Get 软件包进行安装。 https://www.nuget.org/packages/ClosedXML https://www.nuget.org/packages/ClosedXML

Use Value2 to make it fast;使用 Value2 使其快速; Show excel before filling data填充数据前显示excel

There are three ways to do this, 2 of which are mentioned in different answers by others:有三种方法可以做到这一点,其他人在不同的答案中提到了其中的两种:

  1. Directly set the value of a range in excel to the 2D array.直接将excel中某个范围的值设置为二维数组。
  2. Write data to a CSV file, then use interop to save the CSV file as an xls or xlsx file.将数据写入 CSV 文件,然后使用互操作将 CSV 文件另存为 xls 或 xlsx 文件。
  3. Write data to a CSV file, then use the data connections feature to use the CSV as a data source and import the data.将数据写入 CSV 文件,然后使用数据连接功能将 CSV 用作数据源并导入数据。

All the three methods above are very fast.以上三种方法都非常快。 I could write data with a size of 90000 rows and 100 columns in around 6 seconds.我可以在大约 6 秒内写入大小为 90000 行和 100 列的数据。

PS They didn't however solve my problem with formatting the data for borders, font styles, colors, cell merging etc. PS 然而,他们并没有解决我为边框、字体样式、颜色、单元格合并等设置数据格式的问题。

I am answering a little bit late sorry.抱歉,我回答晚了一点。 I was working on my project and we had to use interop excel.我正在处理我的项目,我们不得不使用互操作 excel。 And our data was too big, which was taking more than 1 minute with interop excel.而且我们的数据太大了,用 interop excel 耗时超过 1 分钟。 We tried something else which is copy the all content of datagridview to clipboard, open an excel worksheet using interop excel, and paste the content to excel.我们尝试了其他方法,即将 datagridview 的所有内容复制到剪贴板,使用 interop excel 打开 excel 工作表,然后将内容粘贴到 excel。 It takes less than 1 second and exports our data perfectly.只需不到 1 秒,即可完美导出我们的数据。

DataGridView to string: DataGridView 到字符串:

    var newline = System.Environment.NewLine;
    var tab = "\t";
    var clipboard_string = "";

    foreach (DataGridViewRow row in dgProjeler.Rows)
    {
        for (int i = 0; i < row.Cells.Count; i++)
        {
            if (i == (row.Cells.Count - 1))
                clipboard_string += row.Cells[i].Value + newline;
            else
                clipboard_string += row.Cells[i].Value + tab;
        }
    }

and copy the string to clipboard并将字符串复制到剪贴板

        Clipboard.SetText(clipboard_string);

And open a worksheet, paste the content.并打开工作表,粘贴内容。

        Excel.Application app = new Excel.Application();
        app.Visible = true;
        Excel.Workbook wb = app.Workbooks.Add(1);
        Excel.Worksheet ws = (Excel.Worksheet)wb.Worksheets[1];
        // changing the name of active sheet
        ws.Name = "Exported from gridview";

        ws.Rows.HorizontalAlignment = HorizontalAlignment.Center;
        app.ActiveWindow.Activate();


        ws.Activate();
        ws.Paste();

        ws.Cells.EntireColumn.AutoFit();

It works perfectly on me, I hope it helps people who still couldn't find the solution.它对我很有效,我希望它可以帮助仍然找不到解决方案的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM