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);
}
}
}
}