【问题标题】:How to use FileStream.ReadAsync properly to not blocking UI如何正确使用 FileStream.ReadAsync 不阻塞 UI
【发布时间】:2020-06-23 13:47:01
【问题描述】:

我是异步编程的新手。 我的 UI 中有一个按钮和文本框。我想单击该按钮,然后它将使用 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();
            }

【问题讨论】:

    标签: c# asynchronous async-await task task-parallel-library


    【解决方案1】:

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

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

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

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

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

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

    【讨论】:

    • 我只是想知道为什么这不能正常工作 var bytesRead = await SourceStream.ReadAsync(result, 0, (int)SourceStream.Length); string txt = Encoding.ASCII.GetString(result); txtBox.Text = txt;
    • 这很奇怪。 FileStream constructor 有一个 useAsync 参数。但是File.Opendoesn't use that constructor,这意味着文件访问实际上并不是异步的,即使您使用ReadAsync。为此,您必须自己使用new FileStream()
    • @Jon 抱歉,我刚刚意识到 ReadAllTextAsync() 仅在 .NET Core 中可用。你在使用 .NET Core 吗?
    • 是的,我使用的是 .NET Core。我知道当我们使用带有异步方法的 await 时,它不应该阻塞主线程,所以 UI 应该是响应式的,但奇怪的是它不能以这种方式工作 :)
    • 是的,这只是文件访问异常。 This answer 有令人困惑的解释。
    猜你喜欢
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    • 2013-04-02
    • 2013-04-19
    • 2011-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多