Interop Excel很慢

SAE*_*EED 5 c# excel excel-interop

我正在编写一个应用程序来打开Excel工作表并阅读它

MyApp = new Excel.Application();
MyBook = MyApp.Workbooks.Open(filename);
MySheet = (Excel.Worksheet)MyBook.Sheets[1]; // Explict cast is not required here
lastRow = MySheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell).Row;
MyApp.Visible = false;
Run Code Online (Sandbox Code Playgroud)

这需要大约6-7秒才能完成,这是正常的互操作Excel吗?

还有一种比这更快的阅读Excel的方法吗?

string[] xx = new string[lastRow];
for (int index = 1; index <= lastRow; index++)
{
   int maxCol = endCol - startCol;
   for (int j = 1; j <= maxCol; j++)
   {
      try
      {
         xx[index - 1] += (MySheet.Cells[index, j] as Excel.Range).Value2.ToString();
      }
      catch
      {    
      }

      if (j != maxCol) xx[index - 1] += "|";
   }
}
MyApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(MySheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(MyBook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(MyApp);
Run Code Online (Sandbox Code Playgroud)

xmo*_*jmr 5

附加到 @RvdK 的答案 - 是的 COM 互操作很慢。

为什么慢?

这是由于它的工作原理。从 .NET 发出的每个调用都必须从那里编组到本地 COM 代理,它必须从一个进程(您的应用程序)编组到 COM 服务器(Excel)(通过 Windows 内核内的 IPC),然后从服务器的将本地代理转换为本机代码,其中参数从 OLE 自动化兼容类型编组到本机类型,检查其有效性并执行函数。该函数的结果以大致相同的方式通过两个不同进程之间的多个层返回。

因此,执行每个命令的成本都相当昂贵,执行的命令越多,整个过程就越慢。您可以在网络上找到大量文档,因为 COM 是古老且运行良好的标准(不知何故随着 Visual Basic 6 的消亡)。

此类文章的一个示例如下:http://www.codeproject.com/Articles/990/Understanding-Classic-COM-Interoperability-With-NE

有没有更快的阅读方式?

  1. ClosedXML 可以使用 Microsoft 的 OpenXml SDK 读取和写入 Excel xlsx 文件(甚至是公式、格式等),请参阅此处:https://latedxml.codeplex.com/wikipage ?title=Finding%20and%20extracting%20the%20data&referringTitle=Documentation

  2. Excel数据阅读器声称能够读取旧版和新版Excel数据文件,我自己没有尝试过,请看这里: https: //exceldatareader.codeplex.com/

  3. 另一种更快地读取数据的方法是使用 Excel 自动化将工作表转换为您可以轻松理解的数据文件,并且无需互操作层(例如 XML、CSV)即可进行批处理。这个答案展示了如何做到这一点


Mar*_*ser 3

这个答案只是关于你问题的第二部分。您在那里使用了很多范围,这并不符合预期,而且确实非常慢。

首先读取完整范围,然后迭代结果,如下所示:

var xx[,] = (MySheet.Cells["A1", "XX100"] as Excel.Range).Value2;
for (int i=0;i<xx.getLength(0);i++)
{
    for (int j=0;j<xx.getLength(1);j++)
    {
         Console.WriteLine(xx[i,j].toString());
    }
}
Run Code Online (Sandbox Code Playgroud)

这样会快很多!