C#: How to Perform Async File Operations

C# Programming Guide

Developers can perform resource-intensive I/O (input/output) activities when using asynchrony without blocking the application’s main thread. Further, programmers can leverage asynchrony to improve the performance, responsiveness, and scalability of their .NET applications.

Async file operations are a powerful way to improve the performance of your code by allowing you to parallelize the processing of files. In this programming tutorial, we will examine how to perform async file operations in C# using the Task Parallel Library (TPL).

Looking to learn C# software development in an online course environment? We have a list of the Best Online Courses to Learn C# to help you get started.

What is Asynchronous Programming in C#?

Asynchronous programming may be defined as the process of running programming code in a thread without needing to wait for an I/O-bound or CPU-bound operation to complete. File-system accesses, HTTP requests, API calls, and database queries are examples of I/O-bound operations. Encrypting data, performing sophisticated computations, and managing images or documents are examples of CPU-bound tasks.

Asynchronous programming allows developers to run tasks independently of the main application thread and notify the thread when the task is completed. Asynchrony enables you to complete these activities without disrupting your application’s execution flow or responsiveness. When an async method is called, the calling thread can continue to do other activities while the async method continues to run. This explains why asynchrony can help you enhance the scalability and responsiveness of your application.

Async programming can be helpful when you need to do multiple tasks simultaneously. For example, you might want to read a file from a disk and write it to another location. The read operation usually takes a while, while the write operation would happen immediately. With async programming, you can split the work into two separate tasks so that both processes occur simultaneously thus saving the overall time.

Async File Operations using TPL

To accomplish asynchronous tasks when working with files in .NET, developers can use the BeginRead() and EndRead() methods available in the .NET Framework and earlier versions. Although these techniques are still available in subsequent versions of the .NET Framework, you should use the new keywords async and await in the more recent versions of .NET Framework (4.5 or later) and .NET Core.

What are the Benefits of Asynchronous IO in C#?

Asynchronous IO operations can improve application performance by using fewer resources and reducing the number of threads required to handle requests. Asynchronous methods perform better than synchronous ones because these methods will not block the currently executing thread. An application can perform other tasks while waiting for data from I/O devices such as hard drives or network connections. The benefit increases as your application scales; since more requests can be processed in parallel without blocking the executing threads.

Asynchronous file operations allow you to execute async code in the background while the remaining code of your program continues executing normally. This can be useful if you need to do something like download a large file or process multiple files in sequence.

We highlight some tools to help programmers increase productivity in our tutorial: Productivity Tools for .NET Developers.

How to Perform File Operations in C#

To start using async programming in your projects, you first need to add the AsyncAttribute to your classes and methods. This attribute tells the compiler that the method contains asynchronous code. Then, you can use the Async method on the System.IO.FileStream class to create an asynchronous task object. Task objects have information about the tasks that were initiated, such as the file name, position in the file, and name of the file that was read. You can then use various methods on this object to control the execution of the task.

The following code snippet illustrates how you can create an instance of the FileStream class to open a file for writing data to it:

FileStream fileStream = new FileStream("C:\\test.txt", FileMode.Append, FileAccess.Write, 
FileShare.None, bufferSize: 4096, useAsync: true);

How to Copy Files Asynchronously in C#

The CopyAsync method can be used to copy one or files from a source directory to a target directory. The following code example shows how you can take advantage of the CopyAsync method to copy a file from a source directory to a destination directory in C#:

string fileName = @"D:\Demo\Source\test.txt";
string destinationDirectory = @"D:\Demo\Destination";
using (FileStream source = File.Open(fileName, FileMode.Open))
{
        using (FileStream destination = File.Create(Path.Combine(destinationDirectory, 
       Path.GetFileName(fileName))))
        {
            await source.CopyToAsync(destination);
        }
 }

How to Read a Text File Asynchronously in C#

The ReadAsync method reads bytes from the current file stream and writes them to the memory. Each byte read moves the position in the file stream by n where n is the number of bytes read.

The following code example shows how you can read a file asynchronously in C# using the ReadAsync method:

string fileName = @"D:\Demo\Source\test.txt";
byte[] data;
using (FileStream source = File.Open(fileName, FileMode.Open))
{
    data = new byte[source.Length];
    await source.ReadAsync(data, 0, (int)source.Length);
}

You can use the following code to read text from a file:

var text = await AsyncFileHelper.ReadTextAsync(fileName);
Console.WriteLine(text.ToString());

The following code snippet shows how you can read a text file asynchronously in C#:

public static async Task<List> ReadTextLinesAsync(string path, Encoding encoding)
        {
            var fileTextContent = new List();
            using (var fileStream = new FileStream(path, 
            FileMode.Open, FileAccess.Read, 
            FileShare.Read, bufferSize: 4096, useAsync: true))
            using (var streamReader = new StreamReader(fileStream,
            encoding))
            {
                string text;
                while ((text = await streamReader.ReadLineAsync())
                  != null)
                {
                    fileTextContent.Add(text);
                }
            }
            return fileTextContent;
        }

Here is how you can call the async method ReadTextLinesAsync and display its contents at the console window:

var text = await AsyncFileHelper.ReadTextLinesAsync(fileName, System.Text.Encoding.Default);
foreach(string line in text)
    Console.WriteLine(line);

How to Write a File Asynchronously in C#

You can write text to a file asynchronously using the WriteAsync method of the FileStream class, as shown in the C# code example given below:

public static async Task WriteToFileAsync(string filePath, string text)
{
    byte[] buffer = Encoding.Unicode.GetBytes(text);
    int offset = 0;
    const int Buffer_Size = 4096;
    using var fileStream = new FileStream(filePath, 
    FileMode.Append, FileAccess.Write,
    FileShare.None, bufferSize: Buffer_Size, useAsync: true);
    await fileStream.WriteAsync(buffer, offset, buffer.Length);            
}

You can now use the following code to invoke the WriteToFileAsync method and write a sample text to a file:

string fileName = @"D:\Demo\newtest.txt";
string text = "This is a sample text for testing purposes only.";
await AsyncFileHelper.WriteToFileAsync(fileName, text);

Final Thoughts on Async Operations in C#

Asynchronous IO operations can improve application performance by using fewer resources and reducing the number of threads required to handle requests. Asynchronous methods are better performant than their synchronous counterparts because they do not block the current thread while such methods are executing.

An application can perform other tasks while waiting for data from I/O devices such as hard drives or network connections. You can process more requests in parallel without blocking threads as you scale.

Using asynchronous file operations, you can run code in the background while the rest of your program continues to run. This can be useful if you need to do something like download a large file or process multiple files in sequence.

While asynchronous programming can help avoid thread pool starvation and improve the scalability and performance of the application, it is complex to debug, detect errors and maintain async code.

Read more C# programming tutorials and software development guides.

Joydip Kanjilal
Joydip Kanjilal
A Microsoft Most Valuable Professional in ASP.NET, Speaker, and Author of several books and articles. More than 25 years of experience in IT with more than 18 years in Microsoft .NET and its related technologies. He was selected as a Community Credit Winner at http://www.community-credit.com several times. He has authored 8 books and more than 500 articles in some of the most reputed sites worldwide including MSDN, Info World, CodeMag, Tech Beacon, Tech Target, Developer, CodeGuru, and more.

More by Author

Must Read