Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Петзолд Ч. Программирование для Windows 95 [22].pdf
Скачиваний:
76
Добавлен:
02.05.2014
Размер:
3.02 Mб
Скачать

18

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

Файловый ввод/вывод

Повторим еще раз: для файлового ввода/вывода используйте библиотечные функции языка C везде, где это возможно. Это уже было сделано в программе POPPAD3 в главе 11. Там использовались функции fopen, fseek, fread, fwrite и fclose.

Старый путь

Работа с файлами под Windows постепенно совершенствовалась год от года. В те времена, когда использовались Windows 1.0 и Windows 2.0, единственной функцией файлового ввода/вывода была функция OpenFile, и официально рекомендовавшимся подходом к чтению и записи файлов была запись маленьких файлов на ассемблере, которые непосредственно осуществляли доступ к функциям MS DOS. Хотя использование стандартных функций библиотеки времени выполнения языка C было возможно, в маленькой и средней моделях памяти эти функции работали только с ближними указателями. Это было неудобно в программах, хранивших файлы данных в блоках глобальной памяти. Даже имена файлов, которые часто получали из диалоговых окон, были доступны с помощью дальних указателей.

К счастью, многие программисты вскоре обнаружили несколько недокументированных функций для работы с файлами с использованием дальних указателей. Они имели имена _lopen, _lread, _lwrite и т. д., и содержали непосредственные вызовы функций MS DOS. Начиная с Windows 3.0, эти функции были документированы и приняты как стандартные функции работы с файлами при программировании под Windows. Но применять их при программировании для Windows 95 не рекомендуется.

Отличия Windows 95

Windows 95 реализует несколько усовершенствований файлового ввода/вывода по сравнению с более ранними версиями Windows.

Первое, Windows 95 так же как и Windows 3.1 поддерживает библиотеку диалоговых окон общего пользования (common dialog box library), которая содержит диалоговые окна FileOpen и FileSave. Использование этих диалоговых окон было показано в главе 11. Рекомендуется при программировании использовать именно эти диалоговые окна. При их использовании исчезает необходимость разбора имени файла, который может быть системно-зависимым.

Второе, Windows 95 является 32-разрядной системой. Это значит, что вы можете читать и записывать файл большими блоками информации за один прием, используя однократный вызов функций fread и fwrite (или их эквивалентами, поддерживаемыми Windows 95). Изменения по отношению к существующему коду состоит в том, что отпадает необходимость в использовании циклов при работе с файлами большого размера.

Третье, Windows 95 поддерживает длинные имена файлов. Самое лучшее, что могут делать ваши программы с длинными именами, это просто ничего с ними не делать. (Хорошо звучит, не правда ли?) В документации по Windows сказано, что вы можете использовать данные, возвращаемые функцией GetVolumeInformation, для динамического выделения буферов для хранения имен файлов. Но, обычно в этом нет необходимости. Вам рекомендуется использовать две константы, определенные в файле STDLIB.H: _MAX_PATH (равно 260) и _MAX_FNAME (256) для статического выделения памяти.

Функции файлового ввода/вывода, поддерживаемые Windows 95

Если вы не пользуетесь функциями файлового ввода/вывода стандартной библиотеки времени выполнения языка C, то вы можете использовать функции, поддерживаемые Windows 95. Функция CreateFile является достаточно мощной:

hFile = CreateFile(szName, dwAccess, dwShare, NULL, dwCreate, dwFlags, 0);

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

Для файлов — первый параметр является именем файла. Второй имеет значение либо GENERIC_READ, либо GENERIC_WRITE, либо GENERIC_READ | GENERIC_WRITE. Использование нулевого значения позволяет получить информацию о файле без доступа к его содержимому. Параметр dwShare открывает файл с общими атрибутами, позволяя другим процессам читать из него (FILE_SHARE_READ), или записывать в него

(FILE_SHARE_WRITE), или и то и другое вместе.

19

Флаг dwCreate — это одна из нескольких констант, показывающая, каким образом файл должен быть открыт. Их имена сжаты и прекрасно поясняют суть. Флаг CREATE_NEW вызывает ошибку, если файл уже существует, в то время как флаг CREATE_ALWAYS приводит к удалению содержимого существующего файла. Аналогичным образом, флаг OPEN_EXISTING вызывает ошибку, если файл не существует, а флаг OPEN_ALWAYS создает файл, если он не существует. Флаг TRUNCATE_EXISTING приводит к ошибке, если файл не существует, и удаляет все содержимое, если файл существует.

Параметр dwFlags может быть комбинацией констант, начинающихся со слов FILE_ATTRIBUTE и FILE_FLAG, для установки атрибутов файла и других особенностей.

Функция CreateFile возвращает переменную типа HANDLE. При завершении работы с файлом его необходимо закрыть, используя функцию CloseHandle с описателем файла в качестве параметра. Функции ReadFile и WriteFile похожи:

ReadFile(hFile, pBuffer, dwToRead, &dwHaveRead, NULL);

WriteFile(hFile, pBuffer, dwToWrite, &dwHaveWritten, NULL);

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

Ввод/вывод с использованием файлов, проецируемых в память

При работе в Windows 95 (и это является одним из усовершенствований системы по сравнению с более ранними 16-разрядными версиями Windows) существует возможность читать и записывать данные в файл так, как будто это блок памяти. На первый взгляд это может показаться несколько странным, но со временем становится понятно, что это очень удобный механизм. Это прием рекомендуется использовать также при разделении памяти между двумя и более процессами. Пример такого использования файлов, проецируемых в память, приведен в главе 19 "Динамически подключаемые библиотеки".

Вот простейший подход к вводу/выводу с использованием файлов, проецируемых в память (memory mapped files): Сначала создается обычный файл с использованием функции CreateFile. Затем вызывается функция:

hMap = CreateFileMapping(hFile, NULL, dwProtect, 0, 0, szName);

Параметр dwProtect может принимать одно из следующих значений, и должен быть совместим с режимом разделения файла: PAGE_READONLY, PAGE_WRITECOPY, PAGE_READWRITE. Последний параметр функции

— необязательное имя, обычно используемое для разделения данных между процессами. В этом случае, функция OpenFileMapping открывает тот же файл с указанным именем. Обе функции возвращают значение типа HANDLE.

Если вам необходимо осуществить доступ к части файла, вызовите функцию MapViewOfFile:

p = MapViewOfFile(hMap, dwAccess, dwHigh, dwLow, dwNumber);

Весь файл или его часть могут быть спроецированы в память, начиная с заданного 64-разрядного смещения, которое задается параметрами dwHigh и dwLow. (Очевидно, что dwHigh будет иметь нулевое значение, если файл имеет размер менее 4 ГБ.) Параметр dwNumber задает количество байтов, которое вы хотите спроецировать в память. Параметр dwAccess может быть равен FILE_MAP_WRITE (данные можно записывать и считывать) или FILE_MAP_READ (данные можно только считывать), и должен соответствовать параметру dwProtect функции

CreateFileMapping.

После этого вы можете использовать указатель, возвращаемый функцией, для доступа или модификации данных в файле. Функция FlushViewOfFile записывает на диск все измененные страницы файла, спроецированного в память. Функция UnmapViewOfFile делает недействительным указатель, возвращаемый функцией MapViewOfFile. Затем необходимо закрыть файл, используя функцию CloseHandle.

Мы рассмотрим пример этого процесса в главе, посвященной динамически подключаемым библиотекам.