Программа-пример MMFSparse
Эта программа, «17 MMFSparseexe" (см листинг на рис. 17-4), демонстрирует, как создать проецируемый в память файл, связанный с разреженным файлом NTFS 5 Файлы исходного кода и ресурсов этой программы находятся в каталоге 17-MMFSparse на компакт-диске, прилагаемом к книге После запуска MMFSparse па экране появля ется окно, показанное ниже.
Когда Вы щелкнсте кнопку Create а 1 MB (1024 KB) Sparse MMF, программа попы тается создать разреженный файл «C:\MMFSpanse». Если Ваш диск С не является томом NTFS 5, у программы ничего не получится, и ее процесс завершится А если Вы созда ли том NTFS 5 на каком-то другом диске, модифицируйте мою программу и переком пилируйте ее, чтобы посмотреть, как она работает
После создания разреженный файл проецируется на адресное пространство про цесса. В поле Allocated Kangcs (внизу окна) показывается, какие части файла действи тельно связаны с дисковой памятью. Изначально файл не связан ни с какой памятью, и в этом поле сообщается «No allocated ranges in the file» («В файле нет выделенных диапазонов»).
Чтобы считать байт, просто введите число в поле Offset и щелкните кнопку Read Byte. Введенное Вами число умножается на 1024 (1 Кб), и программа, считав байт по полученному адресу, выводит его значение в поле Byte Если адрес попадает в область, не связанную с физической памятью, в этом поле всегда показывается нулевой байт.
Для записи байта введите число в поле Offset, a значение байта (0-255) — в поле Byte. Потом, когда Вы щелкнете кнопку Wrice Byte, смещение будет умножено на 1024, и байт по соответствующему адресу получит новое значение Операция записи мо жет заставить файловую систему передать физическую память какой-либо части фай ла Содержимое поля Allocated Ranges обновляется после каждой операции чтения или записи, показывая, какие части файла связаны с физической памятью на данный мо мент. Вот как вьплядит окно программы после записи всего одного байта по смеще нию 1 024 000 (1000 x 1024).
На этой иллюстрации видно, что физическая память выделена только одномуди апазону адресов — размером 65 536 байтов, начиняя с логического смещения 983 040 от начала файла С помощью ExpIorer Вы можете просмотреть свойства файла C:\MMFSparbe, как показано ниже.
Заметьте: на этой странице свойств сообщается, что длина файла равна 1 Мб (это виртуальный размер фаЙла), по на деле он занимает на диске только 64 Кб.
Последняя кнопка, Free All Allocated Regions, заставляет программу высвободить всю физическую память, выделенную для файла; таким образом, соответствующее дисковое пространство освобождается, а все байты в файле обнуляются.
Теперь поговорим о том, как работает эта программа. Чтобы упростить ее исход ный код, я создал С++-класс CSparseStream (который содержится в файле Sparse Stream.h) Этот класс инкапсулирует поддержку операций с разреженным файлом или потоком данных (stream). В файле MMFSparse.cpp я создал другой С++-класс, CMMFSparse, производный от CSparseStream. Так что объект класса CMMFSparse обла дает не только функциональностью CSparseStream, но и дополнительной, необходи мой для использования разреженного потока данных как проецируемого в память файла. В процессе создается единственный глобальный экземпляр класса CMMF Sparse — переменная g_mmf. Манипулируя разреженным проецируемым файлом, про грамма часто ссылается на эту глобальную переменную.
Когда пользователь щелкает кнопку Create а 1MB (1024 KB) Sparse MMF, програм ма вызывает CreateFile для создания нового файла в дисковом разделе NTFS 5. Пока что это обычный, самый заурядный файл Но потом я вызываю метод Initialize гло бального объекта g_mmf, передавая ему описатель и максимальный размер файла (1 Мб). Метод Initialize в свою очередь обращается к CreateFileMapping и создает объект ядра «проекция файла» указанного размера, а затем вызывает MapViewOfFile, чтобы сделать разреженный файл видимым в адресном пространстве данного процесса
Когда Initialize возвращает управление, вызывается функция Dlg_ShowAllocated Ranges Используя Windows-функции, она перечисляет диапазоны логических адре сов в разреженном файле, которым передана физическая память. Начальное смеще ние и длина каждого такого диапазона показываются в нижнем поле диалогового окна В момент инициализации объекта g_mmf файлу на диске еще не выделена физичес кая память, и данное поле отражает этот факт.
Теперь пользователь может попытаться считать или записать какие-то байты в пределах разреженного проецируемого файла При записи программа извлекает зна чение байта и смещение из соответствующих полей, а затем помещает этот байт по вычисленному адресу в объект g_mmf. Такая операция может потребовать от файло вой системы передачи физической памяти логическому блоку файла, но программа не принимает в этом участия.
При чтении объекта g_mmf возвращается либо реальное значение байта, если дан ному диапазону адресов передана физическая память, либо 0, если память не передана,
Моя программа также демонстрирует, как вернуть файл в исходное состояние, высвободив все выделенные сму диапазоны адресов (после этого он фактически не занимает места ня диске) Реализуется это так. Пользователь щелкает кнопку Free All Allocated Regions. Однако освободить все диапазоны адресов, выделенные файлу, ко торый проецируется в память, нельзя Поэтому первое, что делает программа, — вы зывает метод ForceClose объекта g_mmf Этот метод обращается к UnmapViewOfFile, а потом — к CloseHandle, передавая описатель объекта ядра «проекция файла».
Далее вызывается метод DecommitPortionOfStream, который освобождает всю па мять, выделенную логическим байтам в файле. Наконец, программа вновь обращает ся к методу Initialize объекча g_mmf, и тот повторно инициализирует файл, проеци руемый на адресное пространство данного процесса. Чтобы подтвердить освобожде ние всей выделенной памяти, программа вызывает функцию Dlg_ShowAllocatedRanges которая выводит в поле строку «No allocated ranges in the file».
И последнее. Используя разреженный проецируемый файл в реальном приложе нии, Вы, наверное, захотите при закрытии файла урезать его логический размер до фактического Отсечение концевой части разреженного файла, содержащей нулевые
байты, не влияет на занимаемый им объем дискового пространства, но позволяет Explorer и команде dir сообщать точный размер файла С этой целью Вы должны пос ле вызова метода ForceClose использовать функции SetFilePointer и SetEndOfFile.
MMFSparse