Клас Stream (і, відповідно, FileStream) підтримує два способи виконання операцій уведення-виведення: синхронний і асинхронний. За умовчанням файли відкриваються в синхронному режимі, тобто подальші оператори виконуються тільки після завершення операцій введення-виведення. Для тривалих файлових операцій ефективніше виконувати уведення-виведення асинхронно, в окремому потоці виконання. При цьому в первинному потоці можна виконувати інші операції.
Для асинхронного уведення-виведення необхідно відкрити файл в асинхронному режимі, для цього використовується відповідний варіант перевантаженого конструктора. Асинхронна операція введення ініціюється за допомогою методу BeginRead. Окрім характеристик буфера, в який виконується введення, в цей метод передається делегат, який задає метод, що виконується після завершення введення.
Цей метод може ініціювати обробку отриманої інформації, відновити операцію читання або виконати будь-які інші дії, наприклад, перевірити успішність введення і повідомити про його завершення. Зазвичай в цьому методі викликається метод EndRead, який завершує асинхронну операцію.
Аналогічно виконується і асинхронне виведення. У лістингу 11.2 приведений приклад асинхронного читання з файлу великого об'єму і паралельного виконання діалогу з користувачем.
Лістинг 11.2. Асинхронне введення
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace examp75
{
class Demo
{
FileStream f;
byte[] buf = new byte[66666666];
AsyncCallback callback;
public void UserInput() // діалог з користувачем
{
string s;
do
{
Console.WriteLine("Введіть рядок. Enter для завершення ");
s = Console.ReadLine();
} while (s.Length != 0);
}
public void OnCompletedRead(IAsyncResult ar) // 1
{
int bytes = f.EndRead(ar);
Console.WriteLine("Налічено " + bytes);
}
public void AsyncRead()
{
try
{
f = new FileStream("1.txt", FileMode.Open,
FileAccess.Read, FileShare.Read, buf.Length, true); // 2
callback = new AsyncCallback( OnCompletedRead ); //3
f.BeginRead( buf, 0, buf.Length, callback, null ); // 4
}
catch (Exception e)
{
Console.WriteLine("Error " + e.Message);
}
}
}
class Program
{
static void Main(string[] args)
{
Demo d = new Demo();
d.AsyncRead();
d.UserInput();
}
}
}
Для зручності сприйняття операції читання з файлу і діалогу з користувачем оформлені в окремий клас Demo.
Метод OnCompletedRead (оператор 1) повинен отримувати один параметр стандартного типу IAsyncResult, що містить відомості про завершення операції, які передаються в метод EndRead.
Файл відкривається в асинхронному режимі, про це говорить значення true останнього параметра конструктора (оператор 2). У операторові 3 створюється екземпляр стандартного делегата AsyncCallback, який ініціалізувався методом OnCompletedRead.
За допомогою цього делегата метод OnCompletedRead передається в метод BeginRead (оператор 4), який створює окремий потік, починає асинхронне введення і повертає управління в потік, що викликає. Зворотний виклик методу OnCompletedRead відбувається при завершенні операції введення. При достатньо довгому файлі verybigfile можна переконатися, що запрошення до введення в методі UserInput видається раніше, ніж повідомлення про завершення операції введення з методу OnCompletedRead.
Приклад, приведений в лістингу 11.2, максимально спрощений для демонстрації методів BeginRead і EndRead, тому в ньому немає необхідних перевірок наявності файлу, успішності читання і так далі.