如何Async Files.ReadAllLines并等待结果?

我有以下代码,

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有很多单词,我读入svariables,我试图使用async并在C#5中使用Async CTP Library await关键字,所以WPF应用程序不会挂起。 到目前为止,我有以下代码,

  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; } 

目标是读取文件中的asynchronous而不是同步,以避免冻结WPF应用程序。

任何帮助表示赞赏,谢谢!

更新File.ReadAll[Lines|Bytes|Text]File.AppendAll[Lines|Text]File.WriteAll[Lines|Bytes|Text]asynchronous版本现在已被合并到.NET Core中 。 这些方法将有望被移植到.NET Framework,Mono等,并被推广到.NET标准的未来版本中。

使用Task.Run ,它本质上是Task.Factory.StartNew的包装,用于asynchronous包装是一种代码异味 。

如果您不想通过使用阻塞函数浪费CPU线程,则应等待真正的asynchronousIO方法StreamReader.ReadToEndAsync ,如下所示:

 using (var reader = File.OpenText("Words.txt")) { var fileText = await reader.ReadToEndAsync(); // Do something with fileText... } 

这将获得整个文件作为一个string而不是一个List<string> 。 如果你需要线,你可以很容易地拆分string,如下所示:

 using (var reader = File.OpenText("Words.txt")) { var fileText = await reader.ReadToEndAsync(); return fileText.Split(new[] { Environment.NewLine }, StringSplitOptions.None); } 

编辑 :这是一些实现与File.ReadAllLines相同的代码的方法,但以真正asynchronous的方式。 该代码基于File.ReadAllLines本身的实现:

 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(); } } 

我也遇到了你的问题中描述的问题。 我已经解决了它,只是简单地说,在以前的答案:

 string[] values; StorageFolder folder = ApplicationData.Current.LocalFolder; // Put your location here. IList<string> lines = await FileIO.ReadLinesAsync(await folder.GetFileAsync("Words.txt");); lines.CopyTo(values, 0); 

尝试这个:

 private async void button1_Click(object sender, RoutedEventArgs e) { button1.IsEnabled = false; try { var s = await Task.Run(() => File.ReadAllLines("Words.txt").ToList()); // do something with s } finally { button1.IsEnabled = true; } } 

编辑:

你不需要试试这个工作。 这实际上只是你需要改变的一行。 解释它是如何工作的:这产生了另一个线程(实际上从线程池获得一个线程)并获取该线程来读取文件。 当文件读完后,button1_Click方法的剩余部分被调用(从GUI线程),结果。 请注意,这可能不是最有效的解决scheme,但它可能是对代码的最简单的更改,不会阻止GUI。