在C#中使用async / await进行文件保存的XElement

时间:2012-09-18 16:46:37

标签: c# filestream xelement async-await c#-5.0

我尝试使用async / await功能从XElement对象编写xml文件。 但我意识到XElement.Save()不能与async / await一起运行。

也许解决方案可以是将XElement.Save(Stream)与FileStream对象一起使用......

所以,我写了一些如下代码,但很难用文件流来处理。

public async Task SaveAsync(XElement xml, string filename)
{
    using (var fs = new FileStream(filename, FileMode.Create))
    {
        xml.Save(fs);
        await fs.WriteAsync(**please_help_me**);
    }
}

如何处理这种方法还是有其他解决方案?

3 个答案:

答案 0 :(得分:5)

如果你真的不想阻止IO(并挂起一个ThreadPool线程/你的线程),你可能需要使用一个临时的MemoryStream:

using(var ms = new MemoryStream())
using(var fs = new FileStream("myFile", FileMode.Create))
{
    xml.Save(ms);
    ms.Position = 0;
    await ms.CopyToAsync(fs)
}

答案 1 :(得分:2)

XElement没有任何异步写入自身的方法,因此您使用它进行的任何调用都是同步的。如果你需要使这个方法异步(例如,这发生在UI线程中,并且你想在后台线程上执行它,以便应用程序在保存XML时看起来不会“冻结”),可能想要开始一项新任务,并将其保存在后台。

public async Task SaveAsync(XElement xml, string filename)
{
    await Task.Factory.StartNew(delegate
    {
        using (var fs = new FileStream("myFile", FileMode.Create))
        {
            xml.Save(fs);
        }
    });
}

答案 2 :(得分:1)

.NET Core 2.0.NET Standard 2.1开始,XElementXDocument都有SaveAsync()方法。因此,您现在可以执行以下操作:

public static async Task SaveAsync(this XElement xml, string filename, SaveOptions options = default, CancellationToken cancellationToken = default)
{
    // "await using" introduced in c# 8 / .NET Core 3.0+
    await using var stream =
        new FileStream(
        filename, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, 
        useAsync: true);

    await xml.SaveAsync(stream, options, cancellationToken);
}

注意:

  • 在.NET Core 3中,XDocument.SaveAsync()(可能还有XElement.SaveAsync())仍然包含至少一个阻塞调用。参见XDocument.SaveAsync has a blocking call #29464。该问题应该在.NET 5中解决。

  • 根据docsuseAsync构造函数的FileStream参数

    指定使用异步I / O还是同步I / O。但是,请注意,底层操作系统可能不支持异步I / O,因此当指定true时,取决于平台,句柄可能会同步打开。异步打开时,BeginRead(Byte[], Int32, Int32, AsyncCallback, Object)BeginWrite(Byte[], Int32, Int32, AsyncCallback, Object)方法在较大的读取或写入操作中表现更好,但对于较小的读取或写入操作可能会慢得多。如果应用程序旨在利用异步I / O,请将useAsync参数设置为true。正确使用异步I / O可以使应用程序加速多达10倍,但是如果不重新设计应用程序以进行异步I / O而使用它则可以使性能下降多达10倍。

    由于您知道要异步编写XElement,因此大概已经为异步I / O设计了应用程序。但是,您可能希望在有和没有异步IO的情况下进行基准测试,以确认您没有损害性能。

演示小提琴here