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(); } Related content feature 14 great preprocessors for developers who love to code Sometimes it seems like the rules of programming are designed to make coding a chore. Here are 14 ways preprocessors can help make software development fun again. By Peter Wayner Nov 18, 2024 10 mins Development Tools Software Development feature Designing the APIs that accidentally power businesses Well-designed APIs, even those often-neglected internal APIs, make developers more productive and businesses more agile. By Jean Yang Nov 18, 2024 6 mins APIs Software Development news Spin 3.0 supports polyglot development using Wasm components Fermyon’s open source framework for building server-side WebAssembly apps allows developers to compose apps from components created with different languages. By Paul Krill Nov 18, 2024 2 mins Microservices Serverless Computing Development Libraries and Frameworks news Go language evolving for future hardware, AI workloads The Go team is working to adapt Go to large multicore systems, the latest hardware instructions, and the needs of developers of large-scale AI systems. By Paul Krill Nov 15, 2024 3 mins Google Go Generative AI Programming Languages Resources Videos