Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаба №1 / books / csharp_ebook.pdf
Скачиваний:
77
Добавлен:
03.03.2016
Размер:
3.69 Mб
Скачать

Programmers Heaven: C# School

Asynchronous Reading and Writing with Streams

Up until now we have only used synchronous reading and writing to streams. Now we will see asynchronous reading and writing to streams. The first obvious question is what asynchronous and synchronous read/write means? Just consider our previous procedure of reading and writing to the stream. We used to call the Read() and Write() methods. For example, we call the Read()method by specifying the amount of data to be read to the supplied array.

byte[] byteText = new byte[fs.Length];

fs.Read(byteText, 0, byteText.Length);

SomeOtherMethod();

When we call the Read() method, our program (or the current thread) is blocked until the data has been read to the supplied array and SomeOtherMethod() is only called when the complete data has been read into the array. This is called a synchronous read, i.e. we are actually waiting till the data is read. The same thing happens with Write(), and this is called a synchronous write. In an asynchronous read and write we just issue the command to read or write through the System.IO.Stream class' BeginRead() and BeginWrite() methods. Once we call BeginRead() or BeginWrite(), two things start simultaneously:

The current thread starts executing the statements following the BeginRead() or BeginWrite() without waiting for the read or write to be completed.

The Common Language Runtime (CLR) starts reading or writing the data and informs our program when it is complete.

So it looks nice! But how does the CLR inform our program that the read or write has been completed? Well asynchronous operations are always implemented in C# using delegates, be it Events, Threads or Asynchronous I/O. So the BeginRead() and BeginWrite() methods take a delegate of type System.AsyncCallback. The delegate AsyncCallback is defined in the System namespace as:

public delegate void AsyncCallback(IAsyncResult ar)

This means that the delegate AsyncCallback can reference any method that has a void return type and takes a parameter of type System.IAsyncResult. The type IAsyncResult can be used to supply information about the asynchronous operation. Most of the time, we don’t bother about this object. A sample method that an AsyncCallback delegate can reference is:

public void OnWriteCompletion(IAsyncResult ar)

{

Console.WriteLine("Write Operation Completed");

}

318

Programmers Heaven: C# School

A demonstration application

Let’s now create a simple console application that demonstrates the use of Asynchronous read/write to streams. The read/write operations in this application will be asynchronous. The source code of the program is:

using System; using System.IO;

using System.Threading;

namespace CSharpSchool

{

class Test

{

static void Main()

{

FileStream fs = new FileStream(@"C:\C-Sharp.txt", FileMode.Open); byte[] fileData = new byte[fs.Length];

Console.WriteLine("Reading file..."); fs.Read(fileData, 0, fileData.Length);

fs.Position = 0;

AsyncCallback callbackMethod = new AsyncCallback(OnWriteCompletion); fs.BeginWrite(fileData, 0, fileData.Length, callbackMethod, null);

Console.WriteLine("Write command issued"); for(int i=0; i<10; i++)

{

Console.WriteLine("Count Reaches: {0}", i);

Thread.Sleep(10);

}

fs.Close();

}

static void OnWriteCompletion(IAsyncResult ar)

{

Console.WriteLine("Write Operation Completed...");

}

}

}

In the above code block, we have defined a delegate instance ‘callbackMethod’ of type AsyncCallback in the Main() method and made it reference the OnWriteCompletion() method. We have created a file stream, read data to the array ‘fileData’ and moved the file pointer position to the start of the file.

319

Programmers Heaven: C# School

We have then started writing to the file using the BeginWrite() method, passing it the same byte array ‘fileData’ and the delegate to the callback method ‘OnWriteCompletion()’.

AsyncCallback callbackMethod = new AsyncCallback(OnWriteCompletion);

fs.BeginWrite(fileData, 0, fileData.Length, callbackMethod, null);

We have then printed numbers in a loop introducing a delay of 10 milliseconds in each iteration. Finally we have closed the stream. Since we have called the BeginWrite() method to write the contents of the file, the main method thread should not block and wait till the writing is complete, it should continue and print the numbers in the loop. When writing to the file is complete, the OnWriteCompletion() method should get called, printing the message on the console. For test purposes, I copied all the text in this lesson to the ‘C-Sharp.txt’ file and executed the program to get the following result:

Reading file...

Write command issued

Count Reaches: 0

Count Reaches: 1

Count Reaches: 2

Write Operation Completed...

Count Reaches: 3

Count Reaches: 4

Count Reaches: 5

Count Reaches: 6

Count Reaches: 7

Count Reaches: 8

Count Reaches: 9

Press any key to continue

Here you can see in the output that after issuing the write command, the main method thread did not get blocked, but continued to print the numbers. Once the write operation was completed, it printed the message while the loop continued to iterate.

Issues Regarding Asynchronous Read/Write

When using asynchronous read/write, certain issues should be considered:

Asynchronous read/write is designed for I/O tasks that take a relatively longer time to complete. It is an overkill to use asynchronous operations for reading and writing small files. This is the reason we have used a relatively larger file in the above demonstration.

In the background, BeginRead() and BeginWrite() create a separate thread and delegate the reading/writing task to this new thread. Hence you can also implement your own BeginRead() and

320

Programmers Heaven: C# School

BeginWrite() methods, for example, for the StreamReader and StreamWriter classes that do not contain these methods.

Important points regarding the use of Streams

The most important thing which must be kept in mind when reading streams is that it is extremely important to close the stream your program created. If you don’t close the stream, the files opened by your program will not be accessible to any other process until your application is closed. These types of bugs are really hard to debug.

It is always a good practice to open a file or stream in a try...catch block as the file specified in the code may not be available during the execution of the code.

It is always a good trick to close the streams in the finally block as it is always guaranteed that the code in finally block will be executed regardless of the presence of exceptions. This way you would be dead sure that the opened stream would be closed.

321

Соседние файлы в папке books