如何正确使用 FileStream.ReadAsync 不阻塞 UI

Jon*_*Jon 0 c# asynchronous task task-parallel-library async-await

我是异步编程的新手。我的用户界面中有一个按钮和文本框。我想单击该按钮,它将使用 FileStream.ReadAsync 方法读取文件,然后它应该在文本框中显示文件的结果。问题是我不想在读取文件时阻止我的 UI。我认为使用 Read 方法应该这样做。但它不起作用。此方法有什么不正确以及如何将 Read 更改为 ReadAsync?

  private  void Button_Click(object sender, RoutedEventArgs e)
        {
            string filename = @"D:\Log\log.txt";
            byte[] result;
            UnicodeEncoding uniencoding = new UnicodeEncoding();
            using (FileStream SourceStream = File.Open(filename, FileMode.Open))
            {
                result = new byte[SourceStream.Length];
                Task<int> tf = new Task<int>(()=> SourceStream.Read(result, 0, (int)SourceStream.Length));
                tf.ContinueWith((x) =>
                 {
                     try
                     {
                         string txt = Encoding.ASCII.GetString(result);
                         Dispatcher.BeginInvoke((Action)(() => txtBox.Text = txt));
                     }
                     catch (Exception ae)
                     {

                         MessageBox.Show(ae.Message);
                     }
                 });

                tf.Start();
            }
Run Code Online (Sandbox Code Playgroud)

Gab*_*uci 6

如果我理解正确并且您只是将文本文件作为 ASCII 编码读取并将内容放入文本框中,那么您最好使用File.ReadAllTextAsync().NET Core 中提供的 :

private async void Button_Click(object sender, RoutedEventArgs e)
{
    string filename = @"D:\Log\log.txt";
    try
    {
        txtBox.Text = await File.ReadAllTextAsync(filename, Encoding.ASCII);
    }
    catch (Exception ae)
    {
        MessageBox.Show(ae.Message);
    }
}
Run Code Online (Sandbox Code Playgroud)

异步读取文件其实有点奇怪。有时即使您使用异步方法读取它,它实际上也不会异步发生。例如,其中一个FileStream构造函数有一个useAsync参数,另一个构造函数有一个options参数,您可以在其中指定FileOptions.Asychronous。但是File.Open()不使用这些构造函数中的任何一个,这意味着文件访问最终不会是异步的,即使您使用ReadAsync(). File.ReadAllTestAsync() 确实

但即使在那里,这个问题也讨论了打开文件的行为实际上不是异步发生的,即使读取是这样,如果您正在访问远程文件系统,这可能是一个问题。因此,如果此代码锁定 UI 有问题,请将该await行更改为:

txtBox.Text = await Task.Run(() => File.ReadAllTextAsync(filename, Encoding.ASCII));
Run Code Online (Sandbox Code Playgroud)

这将ReadAllTextAsync在另一个线程上运行。Task.Run是最好的方法。几乎没有理由使用new Task().