joydip_kanjilal
Contributor

How to perform asynchronous file operations in C#

opinion
Oct 21, 20155 mins
Software Development

Take advantage of the async and await keywords in C# to implement asynchronous file operations

You can take advantage of asynchrony to perform resource-intensive I/O operations sans the need to block the main or the executing thread of the application. Asynchrony when used properly can increase the responsiveness and scalability of your applications to a considerable extent. This article presents an overview on asynchronous file operations using C#.

Why is asynchrony needed?

Asynchronous programming enables you to execute tasks separate from the main application thread, then notifies the thread when its execution is over. Asynchrony helps you execute tasks sans the need of holding up the execution flow or responsiveness of your application. You can leverage asynchrony to improve the performance and responsiveness of your application as the calling thread can continue to perform other operations while the method that can been called asynchronously continues to execute.

The async and await keywords

If you were to use .Net Framework and its earlier versions, you could leverage the BeginRead() and the EndRead() methods to implement asynchronous operations when working with files. Although these methods are still available as part of the newer versions of the .Net Framework, you can use the two new keywords async and await that have been introduced as part of .Net Framework 4.5. Hence, you can take advantage of async and await to implement asynchronous file operations when working with .Net Framework 4.5 or later. You can learn more about async and await on MSDN.

In using asynchrony you can make the user interface threads more responsive and perform other activities while the asynchronous operation is in progress. 

Performing asynchronous file operations

You can use the FileStream class to perform asynchronous I/O operations. In most cases, this would ensure that the calling thread is not blocked while the asynchronous file operation is in progress. To use this option, you should turn on the asynchronous option (with the option useAsync: true) when creating an instance of the FileStream class. This is shown in the code snippet given below.

FileStream fileStream = new FileStream("C:IDG.txt",

                FileMode.Append, FileAccess.Write, FileShare.None,

                bufferSize: 4096, useAsync: true);

The following method writes a text passed to it as parameter to a file asynchronously. Note the usage of the await keyword when calling the WriteAsync() method and the async keyword that is used in the method signature to imply this method would have one or more await statements.

static async Task WriteToFileAsync(string filePath, string text)

        {

            if (string.IsNullOrEmpty(filePath))

                throw new ArgumentNullException("filePath");

            if (string.IsNullOrEmpty(text))

                throw new ArgumentNullException("text");

            byte[] buffer = Encoding.Unicode.GetBytes(text);

            Int32 offset = 0;

            Int32 sizeOfBuffer = 4096;

            FileStream fileStream = null;

            try

            {

                fileStream = new FileStream(filePath, FileMode.Append, FileAccess.Write,

                FileShare.None, bufferSize: sizeOfBuffer, useAsync: true);

                await fileStream.WriteAsync(buffer, offset, buffer.Length);

            }

            catch

            {

                //Write code here to handle exceptions.

            }

            finally

            {

                if(fileStream != null)

                fileStream.Dispose();

            }

        }

It should be noted that if you don’t include the await keyword inside an asynchronous method, the entire method would execute synchronously. Note that the usage of async and await doesn’t create any additional threads. The following code snippet illustrates how you can call the WriteToFileAsync() method from the Main() method to write a text asynchronously.

 static Task WriteToFile()

        {

            string filePath = "C:IDG.txt";

            string text = "Hello Worldrn";

            return WriteToFileAsync(filePath, text);

        }

        static void Main(string[] args)

        {

            WriteToFile().Wait();

            Console.Write("Press any key to exit... ");

            Console.ReadKey();           

        }

The following method reads text from a file asynchronously. You would need to pass the file name and the size of the buffer as parameters. Note how the object readBuffer is set to null in the catch block if an exception occurs so that the caller method can identify if an exception has occurred while attempting to read text from the file.

 static async Task<string> ReadFromFileAsync(string filePath, int bufferSize)

        {

            if (bufferSize < 1024)                 throw new ArgumentNullException("bufferSize");

            if (string.IsNullOrEmpty(filePath))

                throw new ArgumentNullException("filePath");

            StringBuilder readBuffer = null;

            byte[] buffer = new byte[bufferSize];

            FileStream fileStream = null;

            try

            {

                readBuffer = new StringBuilder();

                fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read,

                FileShare.Read, bufferSize: bufferSize, useAsync: true);

                Int32 bytesRead = 0;

                while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0)

                {

                    readBuffer.Append(Encoding.Unicode.GetString(buffer, 0, bytesRead));

                }               

            }

            catch

            {

                readBuffer = null;

                //Write code here to handle exceptions;

            }

            finally

            {

                if (fileStream != null)

                    fileStream.Dispose();

            }

            return readBuffer.ToString();

        }

Note that we have used the FileStream class in the code examples presented in this post as StreamReader and StreamWriter doesn’t provide support for asynchronous read and write operations. You can invoke the ReadFromFileAsync() method from the following method. Note that the ReadFromFile() method given below returns a Task<string> object.

 static async Task<string> ReadFromFile()

        {

            string filePath = "C:IDG.txt";

            return await ReadFromFileAsync(filePath, 4096);

        }

You can now call the ReadFromFile() method from the Main() method to retrieve and display all text from the file in the console window.

<span style="line-height: 1.75em;">static void Main(string[] args)</span>

        {

            string text = ReadFromFile().Result;

            Console.Write(text);      

            Console.ReadKey();            

        }

joydip_kanjilal
Contributor

Joydip Kanjilal is a Microsoft Most Valuable Professional (MVP) in ASP.NET, as well as a speaker and the author of several books and articles. He received the prestigious MVP award for 2007, 2008, 2009, 2010, 2011, and 2012.

He has more than 20 years of experience in IT, with more than 16 years in Microsoft .Net and related technologies. He has been selected as MSDN Featured Developer of the Fortnight (MSDN) and as Community Credit Winner several times.

He is the author of eight books and more than 500 articles. Many of his articles have been featured at Microsoft’s Official Site on ASP.Net.

He was a speaker at the Spark IT 2010 event and at the Dr. Dobb’s Conference 2014 in Bangalore. He has also worked as a judge for the Jolt Awards at Dr. Dobb's Journal. He is a regular speaker at the SSWUG Virtual Conference, which is held twice each year.

More from this author