9

I'm trying to read files asynchronously. I was wondering if this is a proper way to do so. Below is what I have tried so far. Is this correct?

static void Main(string[] args)
{
     Task<string> readFileTask = Task.Run(() => ReadFile(@"C:\Users\User\Desktop\Test.txt"));
     readFileTask.Wait();
     string astr = readFileTask.Result;
     Console.WriteLine(astr);
}

static private async Task<string> ReadFile(string filePath)
{
     string text = File.ReadAllText(filePath);
     return text;
}

Thanks.

Trax
  • 341
  • 4
  • 17
  • Please check this : [How to Async Files.ReadAllLines and await for results?](https://stackoverflow.com/questions/13167934/how-to-async-files-readalllines-and-await-for-results) – Suyash Gaur Jan 12 '20 at 03:39
  • Do you actually want to do this from a Console App? Or do you want to do it from a UI? Because the approach will differ depending on what you want to achieve, – Rowan Smith Jan 12 '20 at 03:40
  • It doesn't look like `System.IO.File` supports async access. Use one of the Stream classes instead (sorry, I'd write up a sample, but I'm on my phone) – Flydog57 Jan 12 '20 at 03:41
  • @RowanSmith Hi, Rowan. Yes, it has to be a console app. – Trax Jan 12 '20 at 03:45
  • @MickyD Hi Micky. Can you please provide sample for this? Thanks. – Trax Jan 12 '20 at 03:46
  • Somewhat relevant: [Why File.ReadAllLinesAsync() blocks the UI thread?](https://stackoverflow.com/questions/63217657/why-file-readalllinesasync-blocks-the-ui-thread) – Theodor Zoulias Nov 16 '20 at 23:31

2 Answers2

11

System.IO provides File.ReadAllTextAsync method for .Net Standard > 2.1 and .NET Core 2.0. If you are using C# 7.1 or higher you can use File.ReadAllTextAsync inside Main function directly.

static async Task Main(string[] args)
{
    var astr = await File.ReadAllTextAsync(@"C:\Users\User\Desktop\Test.txt");
    Console.WriteLine(astr);
}

Unfortunately, If you are not using C# 7.1 or higher then you can't use Async Main. You have to use Task.Run to calll async methods.

static void Main(string[] args)
{
    var astr=Task.Run(async () =>
    {
       return await File.ReadAllTextAsync(@"C:\Users\User\Desktop\Test.txt");
    }).GetAwaiter().GetResult();

    Console.WriteLine(astr);
 }

In case you are using .NET Framework then you have to use FileStream because System.IO not provides File.ReadAllTextAsync method.

private static async Task<string> ReadAllTextAsync(string filePath)  
{  
    using (FileStream sourceStream = new FileStream(filePath,  
        FileMode.Open, FileAccess.Read, FileShare.Read,  
        bufferSize: 4096, useAsync: true))  
    {  
        StringBuilder sb = new StringBuilder();  

        byte[] buffer = new byte[0x1000];  
        int numRead;  
        while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)  
        {  
            string text = Encoding.Unicode.GetString(buffer, 0, numRead);  
            sb.Append(text);  
        }  

        return sb.ToString();  
     }  
}  
habib
  • 2,366
  • 5
  • 25
  • 41
  • Hi, Habib. Thanks for the answer. But I'm getting an exception `File does not contain a definition for ReadAllTextAsync`. I'm currently using Visual Studio 2015. – Trax Jan 12 '20 at 05:24
  • It seems you are using .NET Framework. You have to use FileStream for achieving this. I've updated my answer. – habib Jan 12 '20 at 05:33
  • 1
    Thanks, Habib. It works now! Except I needed to change the encoding to UTF8. – Trax Jan 12 '20 at 07:25
  • 1
    Welcome @Trax. Please make the question accepted if it solves your problem and also votes if helpful. – habib Jan 12 '20 at 07:39
  • I cannot believe in .Net Framework 4.8 there is no async reading of text files! – Vidar Feb 26 '21 at 09:24
2

As it has been said - you can use System.File.ReadAllTextAsync. But in case you need System.File.ReadAllTextAsync(string path) analog for .NET Framework, that is functionally closer to its .NET Core counterpart:

using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;

//...

static async Task<string> ReadAllTextAsync(string path)
{
    switch (path)
    {
        case "": throw new ArgumentException("Empty path name is not legal.", nameof(path));
        case null: throw new ArgumentNullException(nameof(path));
    }

    using var sourceStream = new FileStream(path, FileMode.Open, 
        FileAccess.Read, FileShare.Read, 
        bufferSize: 4096,
        useAsync: true);
    using var streamReader = new StreamReader(sourceStream, Encoding.UTF8, 
        detectEncodingFromByteOrderMarks: true); 
    // detectEncodingFromByteOrderMarks allows you to handle files with BOM correctly. 
    // Otherwise you may get chinese characters even when your text does not contain any

    return await streamReader.ReadToEndAsync();
}

// ...