Асинхронный файловый ввод/вывод в операционной системе WINDOWS, страница 5

Еще одной особенностью функции CreateFile является обслуживание сменных носителей информации. Представьте, что вы пытаетесь получить доступ к файлу, расположенному на гибком магнитном диске или на любом другом сменном носителе информации. Предположим, что носитель данных в настоящее время недоступен (гибкий диск вытащили из дисковода). В этом случае по умолчанию при попытке открыть файл операционная система выведет на экран диалоговое окно с сообщением об ошибке. Если вы хотите избежать этого (обычно, убедившись в отсутствии гибкого диска, приложение принимает меры самостоятельно), необходимо обратиться к вызову SetErrorMode и передать ему в качестве параметра флаг SEM_FAILCRITICALERRORS. В этом случае при отсутствии гибкого диска в дисководе система не будет отображать на экране каких-либо сообщений об ошибках.

Обладая дескриптором файла, вы можете выполнить чтение или запись данных при помощи вызовов ReadFile и WriteFile соответственно. Эти функции работают стандартным образом: в качестве параметров они принимают дескриптор файла, указатель на буфер, длину буфера и указатель на переменную, в которой будет сохранено количество прочитанных или записанных байт. Если используется перекрывающийся ввод/вывод, в качестве одного из аргументов необходимо передать указатель на структуру OVERLAPPED. Для обычных файлов указатель на эту структуру всегда равен NULL. Позже мы с вами увидим, как эта структура используется при перекрывающемся вводе/выводе.

Чтобы закрыть файл, используется вызов СloseHandlе. Этот вызов можно использовать не только для закрытия дескрипторов файлов. С его помощью можно закрыть любой другой дескриптор.

В листинге 1 приведен исходный код простой программы, использующей файловые операции для отображения на экране содержимого одного или нескольких файлов. Вызов CreateFile открывает файл для чтения. После этого вызов GetStdHandle возвращает дескриптор стандартного вывода. Затем при помощи вызовов ReadFile и WriteFile блоками по 4 Кбайт происходит передача содержимого файла с жесткого диска в стандартный поток вывода. Передача продолжается до тех пор, пока программа не обнаружит конец файла.

Листинг 1. Программа NTCAT2

// Ошибки практически не обрабатываются

// Любая ошибка вызовет аварийное завершение программы

#include <windows.h>

// Для удовства использования MessageBox:

void MB(char *s)

{

MessageBox(NULL, s, NULL, MB_OK|MB_ICONSTOP);

}

// Эта программа выполняет основную работу:

void docat(char *fname)

{

HANDLE f=CreateFile(fname, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

HANDLE out=GetStdHandle(STD_OUTPUT_HANDLE);

if (f==INVALID_HANDLE_VALUE)

{

MB("Не могу открыть файл");

exit(1);

}

char buf[4096];

unsigned long n;

do

{

unsigned long wct;

if (!ReadFile(f,buf, sizeof(buf), &n, NULL)) break;

if (n) WriteFile(out, buf, n, &wct, NULL);

} while (n == sizeof(buf));  //если EOF это условие не выполняется

CloseHandle(f);

}

void main(int argc, char *argv[])

{

if (argc==1)

{

MB("Должна быть строка параметров: ntcat FILENAME [FILENAME ....]");

exit(9);

}

// Обработать все указанные файлы

while (--argc) docat(*++argv);

exit(0);

}

Вот так происходит работа с файлами на уровне Win32 API. Обычно при обращении к ReadFile или WriteFile работа программного потока приостанавливается до того момента, когда операция чтения/записи будет завершена. Что если вы этого не хотите? Асинхронный ввод/вывод помогает решить эту проблему. Благодаря механизмам асинхронного ввода/вывода ваша программа может осуществлять ввод/вывод данных и одновременно с этим выполнять какие-либо другие полезные действия, например сложные математические вычисления.

Асинхронный ввод/вывод можно реализовать несколькими разными способами. Проще всего создать новый программный поток и осуществлять весь ввод/ вывод средствами этого потока. Вместо этого можно использовать перекрывающийся ввод/вывод или порты завершения ввода/вывода.