如何异步 Files.ReadAllLines 并等待结果? [英] How to Async Files.ReadAllLines and await for results?
问题描述
我有以下代码,
private void button1_Click(object sender, RoutedEventArgs e)
{
button1.IsEnabled = false;
var s = File.ReadAllLines("Words.txt").ToList(); // my WPF app hangs here
// do something with s
button1.IsEnabled = true;
}
Words.txt
有很多我读入 s 变量的单词,我正在尝试使用 async
和 await
C# 5 中的关键字使用 Async CTP Library
,因此 WPF 应用程序不会挂起.到目前为止,我有以下代码,
Words.txt
has a ton of words which i read into the s variable, I am trying to make use of async
and await
keywords in C# 5 using Async CTP Library
so the WPF app doesn't hang. So far I have the following code,
private async void button1_Click(object sender, RoutedEventArgs e)
{
button1.IsEnabled = false;
Task<string[]> ws = Task.Factory.FromAsync<string[]>(
// What do i have here? there are so many overloads
); // is this the right way to do?
var s = await File.ReadAllLines("Words.txt").ToList(); // what more do i do here apart from having the await keyword?
// do something with s
button1.IsEnabled = true;
}
目标是以异步而不是同步的方式读取文件,以避免 WPF 应用程序冻结.
The goal is to read the file in async rather than sync, to avoid freezing of WPF app.
感谢任何帮助,谢谢!
推荐答案
UPDATE:File.ReadAll[Lines|Bytes|Text]
,File.AppendAll[Lines|Text]
和 File.WriteAll[Lines|Bytes|Text]
现在已经合并到 .NET Core 并随 .NET Core 2.0 一起提供.它们也包含在 .NET Standard 2.1 中.
UPDATE: Async versions of File.ReadAll[Lines|Bytes|Text]
, File.AppendAll[Lines|Text]
and File.WriteAll[Lines|Bytes|Text]
have now been merged into .NET Core and shipped with .NET Core 2.0. They are also included in .NET Standard 2.1.
使用 Task.Run
,它本质上是 Task.Factory.StartNew
的包装器,用于异步包装器 是代码异味.
Using Task.Run
, which essentially is a wrapper for Task.Factory.StartNew
, for asynchronous wrappers is a code smell.
如果不想使用阻塞函数浪费一个 CPU 线程,应该等待真正的异步 IO 方法,StreamReader.ReadToEndAsync
,像这样:
If you don't want to waste a CPU thread by using a blocking function, you should await a truly asynchronous IO method, StreamReader.ReadToEndAsync
, like this:
using (var reader = File.OpenText("Words.txt"))
{
var fileText = await reader.ReadToEndAsync();
// Do something with fileText...
}
这会将整个文件作为 string
而不是 List
.如果你需要行,你可以很容易地在之后拆分字符串,如下所示:
This will get the whole file as a string
instead of a List<string>
. If you need lines instead, you could easily split the string afterwards, like this:
using (var reader = File.OpenText("Words.txt"))
{
var fileText = await reader.ReadToEndAsync();
return fileText.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
}
EDIT:这里有一些方法可以实现与 File.ReadAllLines
相同的代码,但是以真正异步的方式.代码基于 File.ReadAllLines的实现代码>
本身:
EDIT: Here are some methods to achieve the same code as File.ReadAllLines
, but in a truly asynchronous manner. The code is based on the implementation of File.ReadAllLines
itself:
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
public static class FileEx
{
/// <summary>
/// This is the same default buffer size as
/// <see cref="StreamReader"/> and <see cref="FileStream"/>.
/// </summary>
private const int DefaultBufferSize = 4096;
/// <summary>
/// Indicates that
/// 1. The file is to be used for asynchronous reading.
/// 2. The file is to be accessed sequentially from beginning to end.
/// </summary>
private const FileOptions DefaultOptions = FileOptions.Asynchronous | FileOptions.SequentialScan;
public static Task<string[]> ReadAllLinesAsync(string path)
{
return ReadAllLinesAsync(path, Encoding.UTF8);
}
public static async Task<string[]> ReadAllLinesAsync(string path, Encoding encoding)
{
var lines = new List<string>();
// Open the FileStream with the same FileMode, FileAccess
// and FileShare as a call to File.OpenText would've done.
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultBufferSize, DefaultOptions))
using (var reader = new StreamReader(stream, encoding))
{
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
lines.Add(line);
}
}
return lines.ToArray();
}
}
这篇关于如何异步 Files.ReadAllLines 并等待结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!