0

I am new in asynchronous programming. I have a button and textbox in my UI. I want to click on the button and it will Read file using FileStream.ReadAsync method after that it should show the result of the file in the textbox. The problem is I don't want to block my UI while reading file. I thought that with Read method it should be done like this. But it does not work. What is incorrect in this method and how I can change Read to 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();
            }
Jon
  • 21
  • 5

1 Answers1

6

If I'm understanding correctly and you're just reading the text file as ASCII encoding and putting the contents into a text box, then you're better off using File.ReadAllTextAsync(), which is available in .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);
    }
}

Reading files asynchronously is actually a bit weird. Sometimes it doesn't actually happen asynchronously even if you use an asynchronous method to read it. For example, one of the FileStream constructors has a useAsync parameter, and another constructor has an options parameter where you can specify FileOptions.Asychronous. But File.Open() doesn't use either of those constructors, which means that the file access doesn't end up being asynchronous, even if you use ReadAsync(). File.ReadAllTestAsync() does.

But even there, this issue discusses how the act of opening the file doesn't actually happen asynchronously, even if the reading does, which can be an issue if you're accessing a remote file system. So if you have issues with this code locking the UI, then change that await line to this:

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

This will run ReadAllTextAsync on another thread. Task.Run is the best way to do this. There is almost never a reason to use new Task().

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
  • I just wonder why this is not working properly var bytesRead = await SourceStream.ReadAsync(result, 0, (int)SourceStream.Length); string txt = Encoding.ASCII.GetString(result); txtBox.Text = txt; – Jon Jun 23 '20 at 14:56
  • That's the weird part. The [`FileStream` constructor](https://docs.microsoft.com/en-us/dotnet/api/system.io.filestream.-ctor#System_IO_FileStream__ctor_System_String_System_IO_FileMode_System_IO_FileAccess_System_IO_FileShare_System_Int32_System_Boolean_) has a `useAsync` parameter. But `File.Open` [doesn't use that constructor](https://referencesource.microsoft.com/#mscorlib/system/io/file.cs,1a53662a82db3651), which means that the file access doesn't end up actually being asynchronous, even if you use `ReadAsync`. To do it that way, you would have to use `new FileStream()` yourself. – Gabriel Luci Jun 23 '20 at 15:18
  • @Jon Sorry, I just realized that `ReadAllTextAsync()` is only available in .NET Core. Are you using .NET Core? – Gabriel Luci Jun 23 '20 at 15:23
  • Yes, I am using .NET Core. I understand that when we are using await with async methods it should not block the main thread, so the UI should be responsive, but it was strange that it doesn't work in that way :) – Jon Jun 23 '20 at 15:30
  • Yeah, this is just an anomaly of file access. [This answer](https://stackoverflow.com/a/37052176/1202807) has the confusing explanation. – Gabriel Luci Jun 23 '20 at 15:32
  • Because of that anomaly, I thought that I didn't understand async-await correctly :)) thank you! – Jon Jun 23 '20 at 15:39
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/216540/discussion-between-jon-and-gabriel-luci). – Jon Jun 24 '20 at 04:35