如何提高从 OpenXml Excel 电子表格工具中的 SharedStringTable 检索值的性能?

Nei*_*mby 2 .net c# excel openxml

我正在使用DocumentFormat.OpenXml读取 Excel 电子表格。我有一个性能瓶颈,用于从SharedStringTable对象中查找单元格值的代码(它似乎是某种单元格值的查找表):

var returnValue = sharedStringTablePart.SharedStringTable.ChildElements.GetItem(parsedValue).InnerText;
Run Code Online (Sandbox Code Playgroud)

我创建了一个字典以确保我只检索一次值:

if (dictionary.ContainsKey(parsedValue))
{
    return dictionary[parsedValue];
}

var fetchedValue = sharedStringTablePart.SharedStringTable.ChildElements.GetItem(parsedValue).InnerText;
dictionary.Add(parsedValue, fetchedValue);
return fetchedValue;
Run Code Online (Sandbox Code Playgroud)

这将性能时间减少了近 50%。但是,我的指标表明,从SharedStringTable对象中获取值的代码行执行 123,951 次仍然需要 208 秒。有没有其他方法可以优化这个操作?

pet*_*ids 7

我会一次性将整个共享字符串表读入您的字典,而不是根据需要查找每个值。这将允许您按顺序移动文件并存储准备好进行散列查找的值,这将比扫描 SST 以获得您需要的每个值更有效。

在流程开始时运行类似以下内容将允许您使用dictionary[parsedValue].

private static void LoadDictionary()
{
    int i = 0;

    foreach (var ss in sharedStringTablePart.SharedStringTable.ChildElements)
    {
        dictionary.Add(i++, ss.InnerText);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您的文件非常大,您可能会看到使用 SAX 方法而不是上面的 DOM 方法读取文件的一些好处:

private static void LoadDictionarySax()
{
    using (OpenXmlReader reader = OpenXmlReader.Create(sharedStringTablePart))
    {
        int i = 0;
        while (reader.Read())
        {
            if (reader.ElementType == typeof(SharedStringItem))
            {
                SharedStringItem ssi = (SharedStringItem)reader.LoadCurrentElement();
                dictionary.Add(i++, ssi.Text != null ? ssi.Text.Text : string.Empty);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的机器上,使用具有 60000 行和 2 列的文件,使用上述LoadDictionary方法而不是GetValue您问题中的方法大约快 300 倍。该LoadDictionarySax方法提供了类似的性能,但在更大的文件(100000 行和 10 列)上,SAX 方法比该LoadDictionary方法快 25% 左右。在更大的文件(100000 行,26 列)上,该LoadDictionary方法抛出了内存不足异常,但LoadDictionarySax没有问题。