FileStream类中,呼叫Flush(false)Flush(true)之间是有区别的,后者会呼叫cause any buffered data to be written to the file.

然而,目前还不清楚FlushAsync的行为是什么,因为它不接受flushToDisk参数.

我想我真正的问题是,如何确保文件以异步方式写入磁盘?

推荐答案

要确定. NET Core中磁盘流的实际写入/刷新行为需要深入研究源代码,因为正如Jonathan指出的,这里的文档不幸地是不准确的(或者充其量是高度误导).

首先,行为取决于FileStream是否打开缓冲(默认值).如果没有缓冲,则在OSFileStreamStrategy中定义行为.如果它有缓冲,它将OSFileStreamStrategy包装在BufferedFileStreamStrategy中.

从不太常见但更简单的无缓冲情况开始,请参阅FlushAsync覆盖:

public sealed override Task FlushAsync(CancellationToken cancellationToken) => 
       Task.CompletedTask; // no buffering = nothing to flush

事实证明,在非缓冲的情况下,FlushAsync是一个无操作.字节已离开进程,现在掌握在操作系统手中,但操作系统尚未被独立告知将字节刷新到磁盘.

现在请注意该文件中紧随其后的几行:

internal sealed override void Flush(bool flushToDisk)
{
    if (flushToDisk && CanWrite)
    {
        FileStreamHelpers.FlushToDisk(_fileHandle);
    }
}

因此,不仅FlushAsync总是无缓冲的无操作,而且同步Flush方法同样也是无操作,除非指定flushToDisk.这当然会迫使随后的呼叫Win32 FlushFileBuffersUnixfsync.因此,在非缓冲的情况下,问题的简单答案是否定的,没有办法要求OS在关闭流之前将字节写入物理磁盘而不使用同步Flush(bool flushToDisk)过载.

关于更常见的缓冲情况,参见FlushAsyncInternal.你会注意到所有这些做的是拨打OSFileStreamStrategy.WriteAsync,即,它会刷新其内部缓冲区并将字节发送到操作系统,就像它没有缓冲一样,但它不会进一步要求操作系统确保它们被写入磁盘.

在缓冲情况下,同步Flush(bool flushToDisk)overload也将其缓冲器刷新到OS,除了同步.然后,它进一步调用OSFileStreamStrategy.Flush(flushToDisk)——如果flushToDisk为真,它本身就是一个无操作.

所以所有这些都是一个冗长的说法,在所有情况下,FlushAsync只保证字节已发送到操作系统,但不保证操作系统已将这些字节写入磁盘.如果你想让操作系统这样做,你需要调用同步Flush(bool flushToDisk)重载.(我说"询问"是因为,即使这样,也永远不能FlushAsync%保证字节在硬件上,特别是在NAS情况下).

因此,如果你想尽可能保持异步,最好的方法是这样写:

await stream.FlushAsync();
await Task.Run(() => stream.Flush(true));

这两行其实并不多余!如果先调用stream.Flush(true)而不调用await stream.FlushAsync(),前者会同步发送数据到操作系统,阻塞线程,而不是使用更有效的异步操作系统写函数.如果你不使用第二行,操作系统将不会被告知将自己的缓冲区刷新到磁盘.

不幸的是,FlushFileBuffersfsync都是同步的,所以你会希望把stream.Flush(true)包装在Task.Run中,以避免阻塞调用线程,但是在硬件级别上,没有办法以真正异步的方式做到这一点(这是相当不幸的,因为在那个级别上,写入磁盘当然是异步发生的).

Csharp相关问答推荐

错误NU 1301:无法加载源的服务索引

C# uwp中的Win11启动屏幕剪辑工作方式不同

子组件:如何根据另一个组件的状态启用输入

禁用AutoSuggestBox项目更改时的动画?

如何使用C#和Graph API从Azure Directory获取用户详细信息

MongoDB将JS查询转换为C#的问题

带有可选参数的模拟方法返回意外的不同值,具体取决于可选的默认值

对于PowerShell中的ConvertTo-SecureString方法,Microsoft如何将初始化向量添加到AES加密中的安全字符串?

C#按名称从类获取属性值类型<;t>;,我需要反射吗?

为什么C#/MSBuild会自发地为不同的项目使用不同的输出路径?

我可以强制System.Text.Json.JsonSerializer以非递归方式工作吗?

如何使用类似于[SELECT*FROM&Q;&Q;WHERE&Q;]SQL查询的System.Data.Entity创建查询?

根据优先级整理合同列表

C#中COM对象的实际地址

Xamarin中出错.表单:应用程序的分部声明不能指定不同的基类

使用SQL Server 2022+时,我是否必须将代码从SqlConnection类对象中迁移出来?

Excel将';@';添加到具有范围的公式中

我是否以错误的方式使用了异步延迟初始化?

如何在C#中用Serilog记录类路径、方法名和行编号

无法通过服务控制台启动.NET Core 6.0服务(错误1053)