如何异步 Files.ReadAllLines 并等待结果? [英] How to Async Files.ReadAllLines and await for results?

查看:23
本文介绍了如何异步 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 有很多我读入 s 变量的单词,我正在尝试使用 asyncawaitC# 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆