以下是我为 a 创建的辅助方法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.1File.ReadAllLinesAsyn,File.ReadAllTextAsync
似乎也不是完全异步的。您可以查看源代码,它们基于 StreamReader“异步”方法)。
所以,我正在分享一个似乎是目前最有效的方式的实现。\
它比在 中运行同步方法之类的选项要好,因为用它来包装同步代码并期望这是完整的异步流程是Task.Run(()=>File.ReadAllLines(...))
一种非常糟糕的做法。\ 实际上,它打破了真正异步dotnet结构的内部队列机制。Task.Run
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
调用等待耗时: 508毫秒,Task.IsCompleted:True
您可以在评论和这个问题中找到更多信息:File.ReadAllLinesAsync() blocks the UI thread