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

C# 如何在OpenXml Excel电子表格工具中提高从SharedStringTable检索值的性能?,c#,.net,excel,openxml,C#,.net,Excel,Openxml,我正在使用DocumentFormat.OpenXml阅读Excel电子表格。用于从SharedStringTable对象中查找单元格值的代码存在性能瓶颈(它似乎是单元格值的某种查找表): 我创建了一个字典,以确保只检索一次值: if (dictionary.ContainsKey(parsedValue)) { return dictionary[parsedValue]; } var fetchedValue = sharedStringTablePart.SharedString

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

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

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

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

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

我会一次性将整个共享字符串表读入词典,而不是根据需要查找每个值。这将允许您按顺序在文件中移动,并将值隐藏起来,以便进行哈希查找,这将比扫描SST以获得所需的每个值更有效

在流程开始时运行类似于以下的操作将允许您使用
字典[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
工作正常。

我非常喜欢这种方法。在LoadDictionary()中,如何确保单元格值(即数字和查找值)准确映射到字典键?假设sharedStringTablePart.SharedStringTable.ChildElements上的枚举数将以数字顺序从0开始返回它们是否安全?很高兴您喜欢它。是的,完全正确,它们将按顺序阅读。出于兴趣,如果你不介意我问的话,你的表现提高了多少?从208秒提高到0.9秒。非常感谢您分享此技巧,谢谢!
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);
            }
        }
    }
}