Asynchronous I/O

By default, the .NET framework use synchronous I/O, preventing the program to continue it's execution while the I/O is performed. Asynchronous I/O allows you to continue the execution and monitor the I/O execution.

In order to indicate to the framework that you want to use asynchronous I/O, you must create a Stream object using a constructor that allow you to use asynchronous I/O. For the FileStream object, this constructor is:

public FileStream(string path, FileMode mode, FileAccess access, FileShare, int bufferSize, bool useAsync);

To use asynchronous I/O, before calling Read or Write, you must call BeginRead or BeginWrite.

The prototype of those methods are:

public virtual IAsyncResult BeginRead(
   byte[] buffer,           // The buffer to read the data into
   int offset,              // The byte offset in the buffer at which to begin writing data read from the stream
   int count,               // The maximum number of bytes to read
   AsyncCallback callback,  // An optional asynchronous callback, to be called when the read is complete
   object state             // A user provided object that distinguishes this particular asynchronous read request from other requests.
); // Return an IAsyncResult that represents the asynchronous read, which could still be pending.

public virtual IAsyncResult BeginWrite(
   byte[] buffer,           // The buffer to write data from
   int offset,              // The byte offset in buffer from which to begin writing
   int count,               // The maximum number of bytes to write
   AsyncCallback callback,  // An optional asynchronous callback, to be called when the write is complete
   object state             // A user provided object that distinguishes this particular asynchronous write request from other requests
);  // Return an IAsyncResult that represents the asynchronous write, which could still be pending.

There are two ways to be informed when the operation is finished, you can call EndRead or EndWrite passing it the IAsyncResult corresponding to the I/O request you made, or you can pass BeginRead and BeginWrite a callback method to be called when the I/O completes.
If you use the callback approach, the callback method should call EndRead or EndWrite to figure out how many bytes were read or written.

The following code sample demonstrate how to perform an asynchronous I/O on a file stream using the callback method:

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

namespace AsyncTest
{
   /// <summary>
   /// Helper class for the read callback method
   /// </summary>
   public class StateObject
    {
       public byte[] data;
       public FileStream fs;
       public int totalLength;
    }

   /// <summary>
   /// Main program class
   /// </summary>
   public class Test
    {
       public static StateObject sObject = new StateObject();
       private static Mutex mut = new Mutex();
       private static bool mayContinue = false;

       /// <summary>
       /// Callback method for BeginRead
       /// </summary>
       public static void ReadPerformed(IAsyncResult asyncResult)
        {
            StateObject state = (StateObject) asyncResult.AsyncState;
            Stream stream = state.fs;

           int bytesRead = stream.EndRead(asyncResult);
           if (bytesRead != state.totalLength)
                Console.WriteLine("Invalid number of bytes read");

            stream.Close();

           // Displaying read text on screen
           Console.WriteLine(Encoding.ASCII.GetString(state.data, 0, bytesRead));
           Console.WriteLine("-----Ending callback-----");
           mut.WaitOne();
           mayContinue = true;
           mut.ReleaseMutex();
        }

       /// <summary>
       /// The main entry point of the application
       /// </summary>
        [STAThread]
       public static void Main(string[] args)
        {
           // Create the callback object
           AsyncCallback callback = new AsyncCallback(ReadPerformed);
           // Open the file stream
           FileStream fs = new FileStream("c:\\test.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 1, true);
           // Initialize callback specific object
           sObject.fs = fs;
            sObject.totalLength = (int) fs.Length;
            sObject.data = new byte[sObject.totalLength];

           // Initialize Asynchronous read
           fs.BeginRead(sObject.data, 0, sObject.totalLength, callback, sObject);

           // Wait for the operation to be finished by waiting on a mutex
           bool bCont = false;
           do {
                mut.WaitOne();
               if (mayContinue == true)
                    bCont = true;
                mut.ReleaseMutex();
            }
           while(bCont == false);

            Console.WriteLine("Ending Program (Press enter to quit)");
            Console.ReadLine();
        }
    }
}

Continue to: