我正在使用C#中的解析器从多个xml文件中获取数据并将它们放入我自己的数据库中。
现在我的代码有效:
List<CaseFile> caseFiles =
(
from e in XDocument.Load(xmlDoc).Root.Elements("application-information").Elements("file-segments").Elements("action-keys").Elements("case-file")
select new CaseFile
{ (......)
}).toList();
这将创建一个CaseFile对象列表,我稍后将其发送到其他方法以将其数据放入我的数据库中。这个问题是我需要一次解析许多文件,有些文件大到1GB,没有小于200MB,所以这会产生巨大的内存需求。
有没有办法修改我的语句,所以对于它找到的每个CaseFile,它会立即将它发送到其他方法而不必先创建它们的完整列表?
答案 0 :(得分:3)
XDocument.Load
将首先将整个文件加载到内存中。对于快速搜索元素,返回CaseFire对象的IEnumerable
并使用XmlReader
逐节点读取文件(假设您case-file
只有root/application-information/file-segments/action-keys
个节点,否则您需要更多逻辑):
static IEnumerable<CaseFile> FindCaseFiles(string uri)
{
using (XmlReader reader = XmlReader.Create(uri))
{
reader.MoveToContent();
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "case-file")
{
XElement el = XElement.ReadFrom(reader) as XElement;
if (el != null)
yield return new CaseFile() {...};
}
break;
}
}
}
}
用法:
foreach(CaseFile file in FindCaseFiles(path_to_xml))
{
// we have CaseFile here immediately after it found in xml file
}
答案 1 :(得分:0)
只需删除ToList并将您的变量声明为IEnumerable(或者只是使用var)即可。 虽然因为它将所有文件加载到内存中,但可能不会为大文件指示使用linq到XML。您应该考虑使用àXmlReader
答案 2 :(得分:0)
这里的问题是你在LINQ-Expression的结果上调用ToList。这将枚举所有值并将所有内容写入内存。 LINQ-Expression本身不会枚举值。它只会返回一个IEnumerable。 LINQ-Expression不会创建CaseFile对象。
如果只是遍历LINQ-Expression的结果,它将读取另一个值:
var caseFiles = from e in XDocument.Load(xmlDoc).Root.
Elements("application-information").
Elements("file-segments").
Elements("action-keys").
Elements("case-file")
select new CaseFile { ... };
foreach (CaseFile cf in caseFiles)
{
DoTheWork(cf);
}
这样,任何时候都只会创建一个CaseFile对象。