循环遍历单元格时 C# Excel Interop 变慢

标签 c# excel performance office-interop

我试图从 C# 中的 Excel 文档中提取所有文本数据,但遇到了性能问题。在下面的代码中,我打开工作簿,遍历所有工作表,并遍历使用范围内的所有单元格,同时从每个单元格中提取文本。问题是,这需要 14 秒才能执行。

public class ExcelFile
{
    public string Path = @"C:\test.xlsx";
    private Excel.Application xl = new Excel.Application();
    private Excel.Workbook WB;
    public string FullText;
    private Excel.Range rng;
    private Dictionary<string, string> Variables;
    public ExcelFile()
    {
        WB = xl.Workbooks.Open(Path);
        xl.Visible = true;
        foreach (Excel.Worksheet CurrentWS in WB.Worksheets)
        {
            rng = CurrentWS.UsedRange;
            for (int i = 1; i < rng.Count; i++)
            { FullText += rng.Cells[i].Value; }
        }
        WB.Close(false);
        xl.Quit();
    }
}

而在 VBA 中我会做这样的事情,大约需要 1 秒:

Sub run()
    Dim strText As String
    For Each ws In ActiveWorkbook.Sheets
        For Each c In ws.UsedRange
            strText = strText & c.Text
        Next c
    Next ws
End Sub

或者,甚至更快(不到 1 秒):

Sub RunFast()
    Dim strText As String
    Dim varCells As Variant
    For Each ws In ActiveWorkbook.Sheets
        varCells = ws.UsedRange
        For i = 1 To UBound(varCells, 1)
            For j = 1 To UBound(varCells, 2)
                strText = strText & CStr(varCells(i, j))
            Next j
        Next i
    Next ws
End Sub

也许在 C# 的 for 循环中发生了一些我不知道的事情?是否可以将范围加载到数组类型对象中(如我上一个示例中所示)以允许仅对值而不是单元格对象进行迭代?

最佳答案

Excel和C#运行在完全不同的环境中。 C# 在使用托管内存的 .NET 框架中运行,而 Excel 是 native C++ 应用程序并在非托管内存中运行。在这两者之间转换数据(称为“编码”的过程)在性能方面非常昂贵。

调整您的代码无济于事。与编码过程相比,for 循环、字符串构造等都快得惊人。要获得更好性能的唯一方法是减少必须跨越进程间边界的行程数。逐个单元地提取数据永远不会让您获得所需的性能。

这里有几个选项:

  1. 在 VBA 中编写一个子程序或函数来执行您想要的所有操作,然后通过互操作调用该子程序或函数。 Walkthrough .

  2. 使用互操作将工作表保存为 CSV 格式的临时文件,然后使用 C# 打开该文件。您将需要遍历并解析文件以将其转换为有用的数据结构,但此循环会进行得更快。

  3. 使用 interop 将一系列单元格保存到剪贴板,然后使用 C# 直接读取剪贴板。

关于循环遍历单元格时 C# Excel Interop 变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42602592/

相关文章:

vba - 使用 FollowHyperlink 打开打开的 PDF 后将其关闭

vba - 在运行时向工作表添加命令按钮并定义事件

Asp.net 应用程序很慢但 CPU 最大为 40%

javascript - 减少加载大哈希表的正确方法

javascript - 将 jquery 模态弹出脚本附加到按钮事件

c# - 关闭所有子窗体时退出应用程序

c# - 从 DLL/程序集获取实例?

excel - 如何永久添加新的多页选项卡并为其命名?

c# - 是否可以根据类型实现泛型方法的注册?

c++ - 是什么让 STL 如此之快?