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

时间:2017-02-28 12:00:18

标签: c# .net excel openxml

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

var returnValue = sharedStringTablePart.SharedStringTable.ChildElements.GetItem(parsedValue).InnerText;

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

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

var fetchedValue = sharedStringTablePart.SharedStringTable.ChildElements.GetItem(parsedValue).InnerText;
dictionary.Add(parsedValue, fetchedValue);
return fetchedValue;

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

1 个答案:

答案 0 :(得分:4)

我会一次性将整个共享字符串表读入您的字典,而不是根据需要查找每个值。这将允许您按顺序浏览文件并将值保存为散列查找,这比为所需的每个值扫描SST更有效。

在流程开始时运行类似以下内容的内容,您可以使用dictionary[parsedValue]访问每个值。

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

    foreach (var ss in sharedStringTablePart.SharedStringTable.ChildElements)
    {
        dictionary.Add(i++, ss.InnerText);
    }
}

如果您的文件非常大,您可能会看到使用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);
            }
        }
    }
}

在我的计算机上,使用包含60000行和2列的文件,使用上面的LoadDictionary方法而不是问题中的GetValue方法,速度提高了约300倍。 LoadDictionarySax方法提供了类似的性能,但在较大的文件(100000行,10列)上,SAX方法比LoadDictionary方法快约25%。在一个更大的文件(100000行,26列)上,LoadDictionary方法引发了内存不足异常,但LoadDictionarySax没有问题。