"Системное программирование в среде Windows" - читать интересную книгу автора (Харт Джонсон М.)

Создание и открытие файла

Поскольку данная функция является первой из функций Windows, к изучению которых мы приступаем, ее описание будет несколько более подробным по сравнению с остальными; для других функций часто будут приводиться лишь краткие описания. Вместе с тем, даже в случае функции CreateFile будут описаны далеко не все из возможных многочисленных значений ее параметров, однако необходимые дополнительные сведения вы всегда сможете найти в оперативной справочной системе.

Простейшее использование функции CreateFile иллюстрирует приведенный в главе 1 пример ознакомительной Windows-программы (программа 1.2), содержащей два вызова функций, в которых для параметров dwShareMode, lpSecurityAttributes и hTemplateFile были использованы значения по умолчанию. Параметр dwAccess может принимать значения GENERIC_READ и GENERIC_WRITE.

HANDLE CreateFile(LPCTSTR lpName, DWORD dwAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreate, DWORD dwAttrsAndFlags, HANDLE hTemplateFile)

Возвращаемое значение: в случае успешного выполнения — дескриптор открытого файла (типа HANDLE), иначе — INVALID_HANDLE_VALUE.

Параметры

Имена параметров иллюстрируют некоторые соглашения Windows. Префикс dw используется в именах параметров типа DWORD (32-битовые целые без знака), в которых могут храниться флаги или числовые значения, например счетчики, тогда как префикс lpsz (длинный указатель на строку, завершающуюся нулем), или в упрощенной форме — lр, используется для строк, содержащих пути доступа, либо иных строковых значений, хотя документация Microsoft в этом отношении не всегда последовательна. В некоторых случаях для правильного определения типа данных вам придется обратиться к здравому смыслу или внимательно прочесть документацию.

lpName — указатель на строку с завершающим нулевым символом, содержащую имя файла, канала или любого другого именованного объекта, который необходимо открыть или создать. Допустимое количество символов при указании путей доступа обычно ограничивается значением МАХ_РАТН (260), однако в Windows NT это ограничение можно обойти, поместив перед именем префикс \\?\, что обеспечивает возможность использования очень длинных имен (с числом символов вплоть до 32 К). Сам префикс в имя не входит. О типе данных LPCTSTR говорится в одном из последующих разделов, а пока вам будет достаточно знать, что он относится к строковым данным.

dwAccess — определяет тип доступа к файлу — чтение или запись, что соответственно указывается флагами GENERIC_READ и GENERIC_WRITE. Ввиду отсутствия флаговых значений READ и WRITE использование префикса GENERIC_ может показаться излишним, однако он необходим для совместимости с именами макросов, определенных в заголовочном файле Windows WINNT.H. Вы еще неоднократно столкнетесь с именами, которые кажутся длиннее, чем необходимо. 

Указанные значения можно объединять операцией поразрядного "или" (|), и тогда для получения доступа к файлу как по чтению, так и по записи, следует воспользоваться таким выражением:

GENERIC_READ | GENERIC_WRITE

dwShareMode — может объединять с помощью операции поразрядного "или" следующие значения:

• 0 — запрещает разделение (совместное использование) файла. Более того, открытие второго дескриптора для данного файла запрещено даже в рамках одного и того же вызывающего процесса.

• FILE_SHARE_READ — другим процессам, включая и тот, который осуществил данный вызов функции, разрешается открывать этот файл для параллельного доступа по чтению.

• FILE_SHARE_WRITE — разрешает параллельную запись в файл.

Используя блокирование файла или иные механизмы, программист должен самостоятельно позаботиться об обработке ситуаций, в которых осуществляются одновременно несколько попыток записи в одно и то же место в файле. Более подробно этот вопрос рассматривается в главе 3.

lpSecurityAttributes — указывает на структуру SECURITY_ATTRIBUTES. На первых порах при вызовах функции CreateFile и всех остальных функций вам будет достаточно использовать значение NULL; вопросы безопасности файловой системы рассматриваются в главе 15.

dwCreate — конкретизирует запрашиваемую операцию: создать новый файл, перезаписать существующий файл и тому подобное. Может принимать одно из приведенных ниже значений, которые могут объединяться при помощи операции поразрядного "или" языка С.

• CREATE_NEW — создать новый файл; если указанный файл уже существует, выполнение функции завершается неудачей.

• CREATE_ALWAYS — создать новый файл; если указанный файл уже существует, функция перезапишет его.

• OPEN_EXISTING — открыть файл; если указанный файл не существует, выполнение функции завершается неудачей.

• OPEN_ALWAYS — открыть файл; если указанный файл не существует, функция создаст его.

• TRUNCATE_EXISTING — открыть файл; размер файла будет установлен равным нулю. Уровень доступа к файлу, установленный параметром dwAccess, должен быть не ниже GENERIC_WRITE. Если указанный файл существует, его содержимое будет уничтожено. В отличие от случая CREATENEW выполнение функции будет успешным даже в тех случаях, когда указанный файл не существует. 

dwAttrsAndFlags — позволяет указать атрибуты файла и флаги. Всего имеется 16 флагов и атрибутов. Атрибуты являются характеристиками файла, а не открытого дескриптора, и игнорируются, если открывается существующий файл. Некоторые из наиболее важных флаговых значений приводятся ниже.

• FILE_ATTRIBUTE_NORMAL — этот атрибут можно использовать лишь при условии, что одновременно с ним не устанавливаются никакие другие атрибуты (тогда как для всех остальных флагов одновременная установка допускается).

• FILE_ATTRIBUTE_READONLY — этот атрибут запрещает приложениям осуществлять запись в данный файл или удалять его.

• FILE_FLAG_DELETE_ON_CLOSE — этот флаг полезно применять в случае временных файлов. Файл будет удален сразу же после закрытия последнего из его открытых дескрипторов.

• FILE_FLAG_OVERLAPPED — этот флаг играет важную роль при выполнении операций асинхронного ввода/вывода, описанных в главе 14.

Кроме того, существует несколько дополнительных флагов, позволяющих уточнить способ обработки файла и облегчить реализации Windows оптимизацию производительности и обеспечение целостности файлов.

• FILE_FLAG_WRITE_THROUGH — устанавливает режим сквозной записи промежуточных данных непосредственно в файл на диске, минуя кэш.

• FILE_FLAG_NO_BUFFERING — устанавливает режим отсутствия промежуточi ной буферизации или кэширования, при котором обмен данными происходит непосредственно с буферами данных программы, указанными при вызове функций ReadFile или WriteFile (описаны далее). Соответственно требуется, чтобы начала программных буферов совпадали с границами секторов, а их размеры были кратными размеру сектора тома. Чтобы определить размер сектора при указании этого флага, вы можете воспользоваться функцией GetDiskFreeSpace.

• FILE_FLAG_RANDOM_ACCESS — предполагается открытие файла для произвольного доступа; Windows будет пытаться оптимизировать кэширование файла применительно к этому виду доступа.

• FILE_FLAG_SEQUENTIAL_SCAN — предполагается открытие файла для последовательного доступа; Windows будет пытаться оптимизировать кэширование файла применительно к этому виду доступа. Оба последних режима реализуются системой лишь по мере возможностей.

hTemplateFile — дескриптор с правами доступа GENERIC_READ к шаблону файла, предоставляющему расширенные атрибуты, которые будут применены к создаваемому файлу вместо атрибутов, указанных в параметре dwAttrsAndFlags. Обычно значение этого параметра устанавливается равным NULL. При открытии существующего файла параметр hTemplateFile игнорируется. Этот параметр используется в тех случаях, когда требуется, чтобы атрибуты вновь создаваемого файла совпадали с атрибутами уже существующего файла.

Оба вызова функции CreateFile в программе 1.2 максимально упрощены за счет использования для параметров значений по умолчанию, и, тем не менее, они вполне справляются со своими задачами. В обоих случаях было бы целесообразно использовать флаг FILE_FLAG_SEQUENTIAL_SCAN. (Эта возможность исследуется в упражнении 2.3, а соответствующие результаты тестирования производительности приведены в приложении В.)

Заметьте, что для данного файла могут быть одновременно открыты несколько дескрипторов, если только это разрешается атрибутами совместного доступа и защиты файла. Открытые дескрипторы могут принадлежать одному и тому же или различным процессам. (Управление процессами описано в главе 6).

В Windows Server 2003 предоставляется функция ReOpenFile, которая возвращает новый дескриптор с иными флагами, правами доступа и прочим, нежели те, которые были указаны при первоначальном открытии файла, если только это не приводит к возникновению конфликта между новыми и прежними правами доступа.