我想将大型XML文档加载到XDocument对象中。
使用XDocument.Load(path, loadOptions)
的简单同步方法非常好用,但在GUI上下文中加载大文件(尤其是来自网络存储)时会阻塞相当长的时间。
我编写了这个异步版本,旨在提高文档加载的响应能力,特别是在从网络加载文件时。
public static async Task<XDocument> LoadAsync(String path, LoadOptions loadOptions = LoadOptions.PreserveWhitespace)
{
String xml;
using (var stream = File.OpenText(path))
{
xml = await stream.ReadToEndAsync();
}
return XDocument.Parse(xml, loadOptions);
}
然而,在从本地磁盘加载的 200 MB XML 原始文件上,同步版本可以在几秒钟内完成。异步版本(在32位环境下运行)则抛出 OutOfMemoryException
异常:
at System.Text.StringBuilder.ToString()
at System.IO.StreamReader.<ReadToEndAsyncInternal>d__62.MoveNext()
我想这是因为在解析XDocument
时,使用了临时字符串变量来保存原始XML数据。可以想象,在同步场景中,XDocument.Load()
能够通过源文件进行流式传输,并且不需要创建一个巨大的字符串来保存整个文件。
有没有办法兼顾两者优点?使用完全异步I/O加载XDocument
,而无需创建大型临时字符串?
XDocument.Load(stream)
? - DavidGMemoryStream
将整个内容加载到内存中。 然后将MemoryStream.Position
设置为0,并使用XDocument
(同步)加载它。 这样,您就避免了需要创建一个200MB的字符串(这实际上可能会变成400MB,因为.NET UTF-16编码的文件很可能大部分是ASCII,并且使用UTF-8编码到200MB)。 但是,接受的答案允许您完全避免构建单独的缓冲区,在这种环境下,即使有阻塞,它仍然是最佳选择。 - binki