这是我为 NetStandart 2.0 class library 创建的辅助方法,在 NetCore 3.1 和 NetFramework 4.7.2 项目中都使用过。
这些实现与net core 3.1 / net standard 2.1 File类方法的名称和签名完全匹配,因此您只需将它们放在任何公共类中即可。 (例如 FileHelper...):
另外,这应该是最有效的,并且类似于 .net 实现的源代码。
private const int DefaultBufferSize = 4096;
// File accessed asynchronous reading and sequentially from beginning to end.
private const FileOptions DefaultOptions = FileOptions.Asynchronous | FileOptions.SequentialScan;
public static async Task WriteAllTextAsync(string filePath, string text)
{
byte[] encodedText = Encoding.Unicode.GetBytes(text);
using FileStream sourceStream = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.None,
DefaultBufferSize, true);
await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
}
public static async Task<IEnumerable<string>> ReadAllLinesAsync(string filePath)
{
var lines = new List<string>();
using var sourceStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read,
DefaultBufferSize, DefaultOptions);
using var reader = new StreamReader(sourceStream, Encoding.Unicode);
string line;
while ((line = await reader.ReadLineAsync()) != null) lines.Add(line);
return lines;
}
public static async Task<string> ReadAllTextAsync(string filePath)
{
using var sourceStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read,
DefaultBufferSize, DefaultOptions);
using var reader = new StreamReader(sourceStream, Encoding.Unicode);
return await reader.ReadToEndAsync();
}
编辑
显然,StreamReader“异步”方法在返回不完整的任务之前会阻塞当前线程相当长的时间。
(即使 netcore 3.1 File.ReadAllLinesAsyn,File.ReadAllTextAsync 目前似乎也不是完全异步的。您可以查看源代码,它们基于 StreamReader“异步”方法)。
所以,我正在分享一个似乎是目前最有效的实现方式。 \
这比在Task.Run(()=>File.ReadAllLines(...)) 中运行同步方法等选项要好,因为用Task.Run 包装您的 sync 代码并期望这是完整的 async 是一种非常糟糕的做法 流动。 \ 实际上,它打破了真正异步dotnet结构的内部队列机制。
public static async Task<string> ReadAllTextAsync(string filePath)
{
using (var sourceStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read,
DefaultBufferSize, DefaultOptions))
{
var sb = new StringBuilder();
var buffer = new byte[0x1000];
var numRead = 0;
while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
sb.Append(Encoding.Unicode.GetString(buffer, 0, numRead));
return sb.ToString();
}
}
测试时间
这是我的测试及其输出,清楚地显示实际运行是异步:
var stopwatch = Stopwatch.StartNew();
var fileTask = FileHelper.ReadAllTextAsync("48MB_file.txt");
var duration1 = stopwatch.ElapsedMilliseconds;
var isCompleted = fileTask.IsCompleted;
stopwatch.Restart();
await fileTask;
var duration2 = stopwatch.ElapsedMilliseconds;
Console.WriteLine($"Creation took: {duration1:#,0} ms, Task.IsCompleted: {isCompleted}");
Console.WriteLine($"Calling await took: {duration2:#,0} ms, Task.IsCompleted: {fileTask.IsCompleted}");
创建耗时:43 毫秒,Task.IsCompleted:False
调用 await 耗时:508 毫秒,Task.IsCompleted:True
您可以在 cmets 中找到更多信息,在这个问题中:File.ReadAllLinesAsync() blocks the UI thread