我正在编写一种将单独的文本行异步写入文件的方法。如果它被取消,它会删除创建的文件并跳出循环。
这是运行良好的简化代码......我标记了 2 点,我不确定它们是如何处理的。我希望代码在任何情况下都不会阻塞线程。
public async Task<IErrorResult> WriteToFileAsync(string filePath,
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
using var stream = new FileStream(filePath, FileMode.Create);
using var writer = new StreamWriter(stream, Encoding.UTF8);
foreach (var line in Lines)
{
if (cancellationToken.IsCancellationRequested)
{
//
// [1] close, delete and throw if cancelled
//
writer.Close();
stream.Close();
if (File.Exists(filePath))
File.Delete(filePath);
throw new OperationCanceledException();
}
// write to the stream
await writer.WriteLineAsync(line.ToString());
}
//
// [2] flush and let them dispose
//
await writer.FlushAsync();
await stream.FlushAsync();
// await stream.DisposeAsync(); ??????
return null;
}
1我在
Close()
和 FileStream
上调用 StreamWriter
,我认为它会同步运行并阻塞线程。我该如何改进?我不想等待它将缓冲区刷新到文件中然后删除文件。2
我想在
Dispose
范围的末尾将调用 DisposeAsync
方法而不是 using
。 (这个假设正确吗?)。因此,
Dispose
会阻塞线程,并且为了防止我先用FlushAsync
进行刷新,以便Dispose
可以执行更少的操作。 (这在多大程度上是真的?)我也可以删除
using
,而是可以在这两个地方手动编写 DisposeAsync
。但是会降低可读性。如果我用
FileStream
打开 useAsync = true
会在 DisposeAsync
块结束时自动调用 using
吗?对上述代码执行更好的任何解释或变体表示赞赏。
最佳答案
如您所见, using
语句将调用 Dispose()
,而不是 DisposeAsync()
。
C# 8 带来了新的 await using
语法,但由于某种原因,What's new in C# 8.0 文章中没有提到它。
但它是 mentioned elsewhere 。
await using var stream = new FileStream(filePath, FileMode.Create);
await using var writer = new StreamWriter(stream, Encoding.UTF8);
但还要注意,这仅在以下情况下有效:
IAsyncDisposable
或 Stream
类型( FileStream
、 StreamWriter
等)的版本。 即使在 Announcing .NET Core 3.0 的文章中,
IAsyncDisposable
也只是顺便提及,从未展开。另一方面,您不需要这样做(我现在明白为什么了):
writer.Close();
stream.Close();
自the documentation for
Close
says:由于您使用的是
using
, Dispose()
(或 DisposeAsync()
)将被自动调用,并且 Close
不会执行任何尚未发生的事情。因此,如果您确实需要专门关闭文件,但又想异步执行,只需调用
DisposeAsync()
即可。它做同样的事情。await writer.DisposeAsync();
public async Task<IErrorResult> WriteToFileAsync(string filePath,
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await using var stream = new FileStream(filePath, FileMode.Create);
await using var writer = new StreamWriter(stream, Encoding.UTF8);
foreach (var line in Lines)
{
if (cancellationToken.IsCancellationRequested)
{
// not possible to discard, FlushAsync is covered in DisposeAsync
await writer.DisposeAsync(); // use DisposeAsync instead of Close to not block
if (File.Exists(filePath))
File.Delete(filePath);
throw new OperationCanceledException();
}
// write to the stream
await writer.WriteLineAsync(line.ToString());
}
// FlushAsync is covered in DisposeAsync
return null;
}
关于c# - 在C#流上使用DisposeAsync的正确方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58696427/