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

Пятый аргумент определяет, будет ли создан новый файл (CREATE_NEW или CREATE_ALWAYS) или будет открыт существующий файл с указанным именем (OPEN_ EXISTING). Шестой аргумент вызова CreateFile — это набор атрибутов и флагов. Флаги позволяют настроить режим доступа к файлу (например, перекрывающийся ввод/вывод, отключение кэширования, случайный или последовательный доступ и т. п.). Атрибуты являются атрибутами файловой системы («например», «скрытый», «системный», «временный», «только для чтения»). Описание возможных флагов приведено в табл. 2.

Последний, седьмой аргумент вызова CreateFile обычно имеет значение NULL Этому аргументу можно присвоить дескриптор другого открытого файла. И тогда этот, второй файл будет использоваться в качестве шаблона при назначении новому файлу атрибутов файловой системы. Другими словами, если вы используете вызов CreateFilе для создания нового файла и передаете этому вызову дескриптор шаблонного файла, новый созданный вами файл будет обладать всеми атрибутами («скрытый», «только для чтения» и т. п.) шаблонного файла.

Несмотря на то что вызов CreateFile использует достаточно много аргументов, не все эти аргументы применяются каждый раз при обращении к этому вызову. Чаще всего указывается имя файла, метод доступа (GENERIC_READ, GENERIC_WRITE или оба этих значения), ноль в качестве информации о совместном использовании файла, NULL в качестве указателя на структуру атрибутов безопасности, значение CREATE_NEW или OPEN_EXISTING, ноль в качестве набора флагов и атрибутов и NULL в качестве дескриптора шаблонного файла.

Обращаясь к CreateFile, всегда проверяйте значение, возвращаемое этим вызовом, так как при его выполнении могут возникнуть самые разнообразные проблемы. Если создать дескриптор не удалось, вызов вернет значение INVALID_HANDLE_ VALUE. В этом случае необходимо воспользоваться вызовом GetLastError для того, чтобы узнать причину неудачи.

Синхронные операции чтения записи файла

Если файл был открыт при помощи вызова CreateFilе, для его чтения или записи необходимо использовать вызовы ReadFile или WriteFile (соответственно).) Каждый из них принимает в качестве аргументов дескриптор файла, адрес буфера данных и количество байт для чтения или записи. Помимо этого следует указать адрес переменной DWORD, в которой будет сохранено количество реально прочитанных или записанных байт. Каждый из вызовов также принимает указатель на структуру OVERLAPPED. Если вы используете традиционный синхронный метод доступа к файлам, этому аргументу необходимо присвоить значение NULL. Указатель на структуру OVERLAPPED передается в функции чтения/записи только при перекрывающемся или, другими словами, асинхронном вводе/выводе.

В случае неудачи оба вызова возвращают 0 (ноль). Чтобы определить причину неудачи, следует использовать вызов GetLastError. Пример синхронного ввода/вывода с использованием вызовов ReadFile и WriteFile приведен в листингеl.

Определение EOF при синхронном вводе/выводе

Если вы осуществляете синхронное чтение файла (то есть указатель на структуру) OVERLAPPED имеет значение NULL), определить конец файла относительно несложно.) В случае если функция ReadFile встречает конец файла, она читает все данные' вплоть до конца файла. Следующее обращение к ReadFile также будет успешным, однако вызов вернет нулевое количество реально полученных из файла байт.

Обратите внимание на то, что этот метод не сработает в случае, если вы используете перекрывающийся ввод/вывод. Позже, в подразделе «Определение EOF при асинхронном вводе/выводе», будет рассказано о том, как определить конец файла асинхронно.

Дублирование дескрипторов файлов

Дескриптор файла можно дублировать таким образом, чтобы поставить ему в соответствие набор свойств, отличный от изначального. В частности, можно изменить уровень доступа к дескриптору. Для дублирования фактически любых типов дескрипторов используется вызов DuplicateHandle. Этому вызову необходимо передать дескриптор исходного процесса и дескриптор процесса, в рамках которого будет использоваться новый дескриптор. Оба дескриптора могут совпадать. В этом случае дублированный дескриптор будет использоваться в рамках текущего процесса. Чтобы узнать дескриптор текущего процесса, необходимо использовать вызов GetCurrentProcess.