Api функции для программ с проецированием файлов
Не менее мощным и гибким методом организации обмена данными между приложениями является метод, который базируется на проецируемых в память файлах (Files Mapping). Главная идея этого механизма основывается на использовании динамической разделяемой памяти системы для хранения в ней данных. Как известно, каждый процесс имеет свой участок памяти, называемый виртуальным адресным пространством. При использовании механизма проецируемых в память файлов данные становятся доступны из любого процесса, который использует этот файл. В этом случае говорят, что файл отображается в виртуальное адресное пространство процесса, поэтому данные, хранимые в файле, доступны процессу, который этот файл открыл. Механизм проецирования файлов в память используется, например, для исполняемых файлов приложений, а также для DLL.
Для работы с проецируемыми в память файлами существует целый ряд API-функций. Но прежде чем их рассматривать, разберемся в процессе организации обмена данными через проецируемые файлы. На первом этапе необходимо создать объект (файл, отображаемый в память), затем «отобразить» созданный объект в адресное пространство процесса приложения, получая возможность записи и чтения данных их этого файла. При отображении файла на определенный участок памяти (адресного пространства процесса) манипуляции с данными этого участка памяти отражаются на содержимом файла. После произведенных над объектом манипуляций необходимо закрыть доступ к данным файла (удалить проекцию и закрыть файл).
Рассмотрим некоторые функции для работы с проецируемым в память файлом. Для того чтобы создать объект файла, проецируемого в память, можно использовать функцию CreateFileMapping. Ее синтаксис выглядит следующим образом:
Данный текст является ознакомительным фрагментом.
Продолжение на ЛитРес
Сегментированная память
Сегментированная память Понятия памяти и дискового пространства верны только ниже MI. В отличие от OS/ 400, SLIC «знает» о наличии этой памяти и работает с нею. Вся основная память и дисковое пространство в AS/400 находятся внутри большого единого адресного пространства, обычно,
Одноуровневая память
Одноуровневая память Сегодня в компьютерной индустрии модны длинные адреса (в данном случае, «длинный» означает больше 32 разрядов). Практически все производители аппаратуры и ОС начали использовать их в своих продуктах, а в качестве стандарта для следующего поколения
Виртуальная память
Виртуальная память Одноуровневая память AS/400 получила свое имя в честь первопроходцев разработки виртуальной памяти в 60-х годах. Чтобы понять происхождение этого термина, необходимо углубиться в историю.Впервые виртуальная память появилась в компьютере Atlas, созданном в
Исходные файлы и выполняемые файлы
Память
Память HeapSize Функция HeapSize возвращает размер блока памяти, выделенного из кучи функциями HeapAlloc или HeapReAlloc , в байтах. DWORD HeapSize ( HANDLE hHeap , // дескориптор кучи DWORD dwFlags , // контрольные флаги размера кучи LPCVOID lpMem // указатель на память, чей размер возвращается ); Параметры hHeap -
5.5.2 Статическая Память
5.5.3 Свободная Память
5.5.3 Свободная Память Рассмотрим:main() (* table* p = new table(100); table* q = new table(200); delete p; delete p; // возможно, ошибка *)Конструктор table::table() будет вызван дважды, как и деструктор table::~table(). То, что С++ не дает никаких грантий, что для объекта, созданного с помощью new, когда-либо будет вызван
7.7 Свободная Память
7.7 Свободная Память Если вы пользовались классом slist, вы могли обнаружить, что ваша программа тратит на заметное время на размещение и освобождение объектов класса slink. Класс slink – это превоходный пример класса, который может значительно выиграть от того, что программист
7.2.4 Свободная Память
8.5.8 Свободная Память
1.3.3. Оперативная память
1.3.3. Оперативная память Почему эта память — оперативная? Потому что она нужна при выполнении оперативных задач, например открыть Word, запустить почту, посмотреть картинку, поиграть в Квейк и т. д.В оперативную память (ОЗУ, оперативное запоминающее устройство) загружаются
Оперативная память
Оперативная память Из предыдущего раздела должно быть понятно, что процессор – это устройство, обрабатывающее данные, которые хранятся в памяти. В этом разделе главы мы поговорим об одном из типов компьютерной памяти – оперативной памяти, или ОЗУ[4] (рис. 3.2). Рис. 3.2.
СОФТЕРРА: Память на лица, или Лица на память
СОФТЕРРА: Память на лица, или Лица на память Автор: Алексей КлимовВышла девятая версия ACDSee. Судя по объему нововведений, это не «Девятый вал» Айвазовского [Иван Айвазовский, «Девятый вал». 1850 г] и даже не «9 рота» Бондарчука [Федор Бондарчук, «9 рота». 2005 г]. Поэтому в обзоре
4. Память
4. Память Когда вы читаете эту книгу, идете по переполненной улице, слушаете симфонию, успокаиваете плачущего ребенка, ваш мозг набит пространственными и временными паттернами от всех ваших органов чувств. Мир это океан постоянно меняющихся паттернов, которые приходят,
Память завтрашнего дня
Первый шаг в отображении файла - это открытие файла при помощи вызова функции CreateFile . Чтобы гарантировать, что другие процессы не смогут писать в части файла, которая отображается, вам следует открыть файл с монопольным доступом. Кроме того, дескриптор файла должен оставаться открытым до тех пор, пока у процесса не исчезнет нужда в объекте "проецируемый файл". Легкий способ получить монопольный доступ состоит в том, чтобы установить нуль в параметре dwShareMode функции CreateFile. Дескриптор, возвращенный CreateFile используется функцией CreateFileMapping , чтобы создать объект "проецируемый файл".
Функция CreateFileMapping возвращает дескриптор объекта "проецируемый файл". Этот дескриптор должен использоваться при создании представления файла так, чтобы Вы могли получить доступ к совместно используемой памяти. Когда Вы вызываете CreateFileMapping, то задайте имя объекта, число байтов, которые отобразятся из файла и разрешение чтения - записи в отображаемой памяти. Первый процесс, который вызывает функцию CreateFileMapping, создает объект "проецируемый файл". Процессы, вызывающие CreateFileMapping для существующего объекта получают его дескриптор. Вы можете убедиться, успешно или нет завершился вызов CreateFileMapping, который создавал или открывал объект "проецируемый файл", при помощи вызова функция GetLastError . GetLastError возвращает значение NO_ERROR создающему процессу и ERROR_ALREADY_EXISTS последующим процессам.
Функция CreateFileMapping завершается ошибкой, если флажки доступа находятся в противоречии с установленными тогда, когда функция CreateFile открывала файл. Например, чтобы читать и записывать в файл:
- Установите значения GENERIC_READ и GENERIC_WRITE в параметре fdwAccess функции CreateFile.
- Установите значение PAGE_READWRITE в параметре fdwProtect функции CreateFileMapping.
Процедура создания объекта "проецируемый файл" не закрепляет физическую память, она только резервирует её.
Размер проецируемого в память файла
Размер объекта "проецируемый файл" не зависит от размера отображаемого файла. Однако, если объект "проецируемый файл" является большим чем файл, система увеличивает файл до возвращения значения функцией CreateFileMapping. Если объект "проецируемый файл" является меньшим чем файл, система проецирует только определенное число байтов из файла.
Параметры dwMaximumSizeHigh и dwMaximumSizeLow функции CreateFileMapping дают возможность устанавливать число байтов, которые будут отображаться из файла:
-
Windows 95/98/Me: Параметр dwMaximumSizeHigh не используется, потому что эти операционные системы не поддерживаются 32-разрядной файловой системой. Это значение должно быть - нуль.
Если Вы не хотите изменять размер файла (например, когда отображаете файл только для чтения) вызовите функцию CreateFileMapping и установите оба её параметра dwMaximumSizeHigh и dwMaximumSizeLow в нуль. Выполнение этого приема создает объект "проецируемый файл" точно такого же размера, как и файл. В противном случае, Вы должны вычислить или приблизительно подсчитать размер законченного файла, потому что объекты "проецируемый файл" являются статическими по размеру; после создания их размер не может увеличиться или уменьшиться. Попытка проецировать файл с нулевой длиной этим способом завершается ошибкой с кодом ошибки ERROR_FILE_INVALID . Программы должны обнаруживать файлы с нулевой длиной и отвергать такие файлы:
Размер объекта "проецируемый файл" выбирается при помощи контроля, как далеко в файле с отображением в памяти Вы можете "видеть". Если Вы создаете 500 килобайтный объект "проецируемый файл" , Вы имеете доступ только к первым 500 КБ файла, независимо от размера его файла. Так как, чтобы создать больший объект "проецируемый файл", не требуется от Вас системных ресурсов, создайте его по размерам одинаковым с файлом (установив нули в обоих параметрах dwMaximumSizeHigh и dwMaximumSizeLow функции CreateFileMapping), даже если Вы не предполагаете просматривать весь файл. В затраты системных ресурсов входит создание представлений и доступа к ним.
Если Вы хотите просмотреть часть файла, которая начинается не в начале файла, Вы должны создать объект "проецируемый файл". Этот объект - размер части файла, который Вы хотите просмотреть плюс смещение в файле.
Не менее мощным и гибким методом организации обмена данными между приложениями является метод, который базируется на проецируемых в память файлах (Files Mapping). Главная идея этого механизма основывается на использовании динамической разделяемой памяти системы для хранения в ней данных. Как известно, каждый процесс имеет свой участок памяти, называемый виртуальным адресным пространством. При использовании механизма проецируемых в память файлов данные становятся доступны из любого процесса, который использует этот файл. В этом случае говорят, что файл отображается в виртуальное адресное пространство процесса, поэтому данные, хранимые в файле, доступны процессу, который этот файл открыл. Механизм проецирования файлов в память используется, например, для исполняемых файлов приложений, а также для DLL.
Для работы с проецируемыми в память файлами существует целый ряд API-функций. Но прежде чем их рассматривать, разберемся в процессе организации обмена данными через проецируемые файлы. На первом этапе необходимо создать объект (файл, отображаемый в память), затем "отобразить" созданный объект в адресное пространство процесса приложения, получая возможность записи и чтения данных их этого файла. При отображении файла на определенный участок памяти (адресного пространства процесса) манипуляции с данными этого участка памяти отражаются на содержимом файла. После произведенных над объектом манипуляций необходимо закрыть доступ к данным файла (удалить проекцию и закрыть файл).
Рассмотрим некоторые функции для работы с проецируемым в память файлом. Для того чтобы создать объект файла, проецируемого в память, можно использовать функцию CreateFileMapping. Ее синтаксис выглядит следующим образом:
- hFile - должен содержать дескриптор открытого файла, для которого будет создаваться объект, отображающий этот файл в память процесса.
- lpFileMappingAttributes - указатель на структуру TSecurityAttributes. Если указателю присвоить nil, то атрибуты защиты устанавливаются по умолчанию.
- flProtect - содержит флаги, которые задают режимы доступа к виду файла в памяти процесса. Этот параметр может принимать одно из следующих значений:
- PAGE_READONLY — из вида файла можно только читать данные;
- PAGE_READWRITE — разрешает чтение и запись данных в вид файла;
- PAGE_WRITECOPY — разрешает чтение и запись данных в вид файла, но при записи создается новая копия вида файла.
В случае успешного завершения эта функция возвращает дескриптор объекта (THandle), отображающего файл в память, а в случае неудачи — 0.
После того как проецируемый файл был создан, необходимо отобразить его в адресное пространство процесса. Для этого предназначена функция MapViewOfFile, имеющая следующий синтаксис:
- hFileMappingObject - должен содержать дескриптор объекта, отображающего файл в память, который был предварительно создан функцией CreateFileMapping.
- dwDesiredAccess - задает режим доступа к виду файла и может принимать одно из следующих значений:
- FILE_MAP_WRITE - чтение и запись в вид файла;
- FILE_MAP_READ — только чтение из вида файла;
- FILE_MAP_ALL_ACCESS — чтение и запись в вид файла;
- FILE_MAP_COPY — при записи в вид файла создается его копия, а исходный файл не изменяется.
В случае успешного завершения функция возвращает указатель на вид файла в адресном пространстве процесса, а случае неудачи — nil. Параметры этой функции имеют следующее назначение.
Следующей функцией, противоположной по производимым действиям функции MapViewOfFile, является UnMapViewOfFile. Она отключает проецируемый файл от текущего процесса:
Функция принимает указатель, возвращаемый MapViewOfFile, и использует его для отмены проекции файла на адресное пространство процесса. В случае успешной выгрузки функция возвращает True, в противном случае — False.
И последняя функция, которую необходимо рассмотреть, — это CloseHandle. Она используется для закрытия дескриптора (многих системных объектов, а не только проекции файла).
Как видно из синтаксиса функции, она принимает описатель объекта файлового отображения, полученный в результате выполнения функции CreateFileMapping и освобождает его. Для правильного завершения работы с объектом файлового отображения сначала следует применить функцию UnMapViewOfFile, а затем CloseHandle.
Сама проекция файла будет удалена только после того, как будут закрыты все дескрипторы во всех использующих эту проекцию процессах.
Для демонстрации работы проецируемых в память файлов создадим приложение, которое будет записывать в такой файл строку и спустя некоторое время считывать ее оттуда. Для этого нам понадобится стандартный TextBox, кнопка, метка и таймер. Программа будет работать следующим образом: строка, записанная в поле редактора, после нажатия кнопки помещается в проецируемый файл. Далее, спустя некоторое время (задается таймером = 1 сек.), содержимое файла считывается и задается в качестве заголовка метки.
В секцию описания переменных программы помещаем следующие объявления:
Создание проецируемого файла, его отображение в адресное пространство процесса и копирование данных в проецируемый файл выполняется в момент щелчка по кнопке.
После того как будет нажата кнопка, данные помещаются в проецируемый файл. По истечении 1 секунды, заданного таймером, строка устанавливается в качестве текста метки Label2.
В момент завершения приложения необходимо отключить проецируемый файл от адресного пространства процесса и закрыть объект файла. Эти действия можно выполнять в момент уничтожения формы.
Используемая литература: Программирование в Delphi. Трюки и эффекты. Александр Чиртик
Не доходит одна вещь. Делаю отображение проекции большого файла (например, 1Гб). Делаю, в отображении, перемещение данных. Например, смещаю данные, равные размеру файла минус 10 байтов, на 10 байтов в сторону старших адресов. Получается перемещение данных размером в 1Гб - 10 байтов. По времени операции видно, что это всё происходит в памяти (быстро). Как и когда эти изменения попадают на физический жёсткий диск? Ведь как-то они должны туда попасть? Проекция проекцией, но нужно же и запись в файл как-то сделать. Если запись делается, то это, по времени, должна быть не быстрая операция, но этого не наблюдаю.
Проецирование звука в память
Доброго времени суток форумчане. Завис над одной проблемой и не могу придумать выход. Есть у меня.Заменить в текстовом файле все строчные буквы на прописные и удвоить вхождение каждой цифры (проецирование в память)
С помощью механизма проецирования в память замените в текстовом файле все строчные буквы на.проецирование файла
Ребята помогите справится с заданием, нужно спроецировать файл данных, в спроецированном файле.Проецирование файла данных
ПОМОГИТЕ ПОЖАЛУЙСТА Проецировать файл данных. В спроецированом файле поменять местами первую и.Система сбрасывает изменения на диск не сразу, а в отложенном режиме (lazy).
Именно поэтому это происходит незаметно. Но ее можно "попросить" - FlushViewOfFile.Вот это и не понятно. Вернеее, с небольшими объемами понятно, но как можно незаметно сбросить на жёсткий диск 2Гб?
Сбросили 100-200 Мегабайт. Секунды через три-четыре сбросили еще столько же. И т.д.
Добавлено через 18 минут
P.S. Кстати, сбрасывается на диск ведь не все отображение, а только измененные страницы.
Так что ситуации с flush=2GB на практике встречаются редко.P.S. Кстати, сбрасывается на диск ведь не все отображение, а только измененные страницы.
Так что ситуации с flush=2GB на практике встречаются редко.А в примере, который я привёл в первом посте, там же прийдётся весь файл переписать, отдельными страницами не обойтись? Или я не так понимаю? Сейчас попробовал с файлом в 2Гб сделать FlushViewOfFile. Получилось 20 секунд на сброс, т.е. если частями по 100-200 мгб делать, то вполне незаметно может получиться. А при создании отображеня проекции какое-то чтение с файла происходит или всё как-то через адреса делается?
Насчёт проецирования пишут, что память не выделяется, но резервируется. В чём разница? Памяти, которая выделяется для приложения, всё равно должно хватать, чтобы отображение проекции поместилось? Или это какая-то другая память, а не та что выделяется для приложения.Проецирование - это просто отметка в соответствующей структуре, что вот этот виртуальный адрес "указывает вот сюда вот в файл". Подкачка страницы в физическую (ОЗУ) память происходит только при обращении к данным. Тогда выделяется физическая память.
Запись в файл - происходит только в том случае, если установлен флажок изменения для конкретной страницы. В удобный для ОС момент (либо принудиловка при FlushViewOfFile). Также не забывайте про файловый буфер. Если файл есть в буфере в основной памяти, то ОС не будет считывать его с диска.Памяти, которая выделяется для приложения, всё равно должно хватать, чтобы отображение проекции поместилось? Или это какая-то другая память, а не та что выделяется для приложения.
В проекте win32 не удаётся и 1,5 Гб спроецировать (максимум 1,2 - 1,3), если проект x64, тогда и 3Гб получается.
Добавлено через 1 минуту
Запись в файл - происходит только в том случае, если установлен флажок изменения для конкретной страницы.
А в примере, который я привёл в первом посте, там же прийдётся весь файл переписать, отдельными страницами не обойтись? Или я не так понимаю?
Решение
А в примере, который я привёл в первом посте, там же прийдётся весь файл переписать, отдельными страницами не обойтись? Или я не так понимаю?
Да, все правильно. Там изменения затрагивают все отображение, поэтому все страницы памяти,
которые оно занимает, будут сброшены в файл.А при создании отображеня проекции какое-то чтение с файла происходит или всё как-то через адреса делается?
Происходит. Но этот процесс отличается от обычного чтения файла.
Упрощенно говоря, отображение - это когда страницы виртуальной памяти разных процессов
отображаются на одни и те же физические адреса. Один процесс записал что-то в отображение -
все остальные сразу видят изменения. Файл, отображаемый в память (Memory-Mapped File, MMF) -
это все то же отображение, только каждая страница памяти этого отображения связана с
определенным местом в файле на диске. При доступе на чтение содержимое страницы загружается
из файла, - здесь работает тот же механизм, который используется в файле подкачки, в момент
доступа к страницам памяти, которые физически не присутствуют на месте, - а при доступе
на запись страница помечается как "dirty". Работающий в системе "lazy writer" постепенно
сбрасывает dirty-страницы на диск, но делает это аккуратно, в фоне, чтобы не мешать работе
других приложений.Память может быть в состоянии "committed" (т.е. зафиксирована, или, как говорят, закоммичена) и
"reserved" (зарезервирована). Разница в том, что committed-страницы должны быть обеспечены
реальным ресурсом памяти, а reserved - это лишь пометка "не занимать", что память будет
использована в будущем. Выделять reserved-страницы только затем, чтобы потом сразу сделать их
committed, большого смысла не имеет, обычно разделение на reserve/commit делается для каких-то
конкретных целей.Памяти, которая выделяется для приложения, всё равно должно хватать, чтобы отображение проекции поместилось? Или это какая-то другая память, а не та что выделяется для приложения.
Все упирается в лимиты адресного пространства. Например, на 32-битных Windows не получится создать
отображение размером порядка 2 Гигабайт. Хотя сам MMF может быть намного больше.
На x64 таких ограничений нет.Теория:
Файл, спроецированный на память - это механизм Win32 API, позволяющий любой открытый файл рассматривать как блок пямяти с произвольным доступом (все записи и чтения байта по адресу, лежащему в пределах такого блока, приводят к изменению соотв. байта в файле). Это может быть очень удобно, когда необходимо работать с файлами очень большого объема: вместо того, чтобы читать всё содержимое файла в память (или искать нужный фрагмент функцией Seek), можно спроецировать файл на память и сразу прочитать или модифицировать нужный фрагмент памяти. Windows подгружает спроецированный файл постранично, по мере обращения к тем или иным адресам памяти; всё делается автоматически, на уровне механизма виртуальной памяти Win32, что избавляет от необходимости вручную следить за подгрузкой из файла или записью в файл ненужных участков памяти.Пример на MFC:
Чтобы упростить себе жизнь, создадим простой класс на основе CFile (класс-предок будет заниматься открытием и закрытием файлов; нам же останется только реализовать в нашем классе пару функций для проецирования файла):код C++
class CMemoryMappedFile: public CFile
<
protected:
HANDLE m_hMapping; // хэндл объекта "проекция файла"
void *m_bufMapping; // стартовый адрес проекции
public: // набор конструкторов
CMemoryMappedFile()
CMemoryMappedFile(char *strFileName, UINT openFlags): CFile(strFileName, openFlags)
~CMemoryMappedFile()
public: // пара функций "спроецировать" / "освободить проекцию"
void *GetMemoryMapping(bool bReadOnly=false);
void ReleaseMemoryMapping();
>;
// функция проецирует файл на память (файл должен быть уже открыт)
// и возвращает стартовый адрес блока памяти
void *CMemoryMappedFile::[b]GetMemoryMapping(bool bReadOnly)[/b]
<
if(!m_hFile || m_hMapping) return NULL;
m_hMapping = CreateFileMapping((void*)m_hFile, 0, bReadOnly?PAGE_READONLY:PAGE_READWRITE, 0, 0, 0);
if(!m_hMapping) return NULL;
m_bufMapping = MapViewOfFile(m_hMapping, FILE_MAP_READ|(bReadOnly?0:FILE_MAP_WRITE), 0, 0, 0);
if(!m_bufMapping) CloseHandle(m_hMapping);
return m_bufMapping;
>
// освобождение проекции
void CMemoryMappedFile::[b]ReleaseMemoryMapping[/b]()
<
if(!m_hMapping) return;
UnmapViewOfFile(m_bufMapping);
CloseHandle(m_hMapping);
m_hMapping = NULL;
>
// ===============================================
// пример - создадим текстовый файл на диске С: и запишем
// в него строку текста, затем заменим третий символ на "Z":
void DemoFileMapping()
<
CMemoryMappedFile file("c:\\1.txt", CFile::modeCreate|CFile::modeReadWrite);
char *str = "ABCDEFG";
file.Write(str, strlen(str));
char *buf = (char*)file.GetMemoryMapping();
buf[2] = 'Z';
file.ReleaseMemoryMapping();
>Пример на "чистом" WinAPI:
код C++
// пример - создадим текстовый файл на диске С: и запишем
// в него строку текста, затем заменим третий символ на "Z":
void DemoFileMapping()
<
HANDLE hFile = CreateFile ( "c:\\1.txt", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);DWORD d;
char *str = "ABCDEFG";
WriteFile(hFile, str, strlen(str), &d, 0);HANDLE mapping = CreateFileMapping(hFile, 0, PAGE_READWRITE, 0, 0, 0);
if(mapping)
<
char *buf = (char *)MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if(buf)
<
buf[2] = 'Z';
UnmapViewOfFile(buf);
>
CloseHandle(mapping);
>
CloseHandle(hFile);
>Читайте также: