5.3.2. Примеры программ

We use cookies. Read the Privacy and Cookie Policy

5.3.2. Примеры программ

В этом разделе рассматриваются две программы, в которых иллюстрируются чтение и запись файлов, отображаемых в памяти. Первая программа (листинг 5.5) генерирует случайное число и записывает его в отображаемый файл. Вторая программа (листинг 5.6) читает число из файла, выводит его на экран, а затем умножает на 2 и записывает обратно в файл. Обе программы принимают имя файла из командной строки.

Листинг 5.5. (mmap-write.c) Запись случайного числа в файл, отображаемый в памяти

#include <stdlib.h>

#include <stdio.h>

#include <fcntl.h>

#include <sys/mman.h>

#include <sys/stat.h>

#include <time.h>

#include <unistd.h>

#define FILE_LENGTH 0x100

/* получение случайного числа в диапазоне [low,high]. */

int random_range(unsigned const low, unsigned const high) {

 unsigned const range = high - low + 1;

 return

  low + (int)(((double)range) * rand() / (RAND_MAX + 1.0));

}

int main (int argc, char* const argv[]) {

 int fd;

void* file_memory;

 /* Инициализация генератора случайных чисел. */

 srand(time(NULL));

 /* подготовка файла, размер которого будет достаточен для

    записи беззнакового целого числа. */

 fd = open(argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

 lseek(fd, FILE_LENGTH+1, SEEK_SET);

 write(fd, "", 1);

 lseek(fd, 0, SEEK_SET);

 /* Создание отображаемой области. */

 file_memory =

  mmap(0, FILE_LENGTH, PROT_WRITE, MAP_SHARED, fd, 0);

 close(fd);

 /* Запись случайного числа в отображаемую память. */

 sprintf((char*)file_memory,

  "%d ", random_range(-100, 100));

 /* Освобождение памяти (не обязательно, так как программа

    завершается). */

 munmap(file_memory, FILE_LENGTH);

 return 0;

}

Программа mmap-write пытается открыть файл и, если он не существует, создает его. Третий аргумент функции open() указывает на то, что файл доступен для чтения/записи. Поскольку длина файла неизвестна, с помощью функции lseek() мы убеждаемся в том, что файл имеет достаточную длину для записи беззнакового целого числа, а затем возвращаемся в начало файла.

Программа закрепляет файл за областью памяти и закрывает его дескриптор, так как в нем больше нет необходимости. После этого программа записывает случайное число в отображаемую память, т.е. в файл, и освобождает память. В принципе, вызывать функцию munmap() нет необходимости, так как ОС Linux автоматически освободит память при завершении программы.

Листинг 5.6. (mmap-read.c) Чтение случайного числа из файла, отображаемого в памяти

#include <stdlib.h>

#include <stdio.h>

#include <fcntl.h>

#include <sys/mman.h>

#include <sys/stat.h>

#include <unistd.h>

#define FILE_LENGTH 0x100

int main(int argc, char* const argv[]) {

 int fd;

 void* file_memory;

 int integer;

 /* Открытие файла. */

 fd = open(argv[1], O_RDWR, S_IRUSR | S_IWUSR);

 /* Создание отображаемой области. */

 file_memory =

  mmap(0, FILE_LENGTH, PROT_READ | PROT_WRITE,

  MAP_SHARED, fd, 0);

 close(fd);

 /* Чтение целого числа и вывод его на экран. */

 sscanf(file_memory, "%d", &integer);

 printf("value: %d ", integer);

 /* Удваиваем число и записываем его обратно в файл. */

 sprintf((char*)file_memory, "%d ", 2 * integer);

 /* Освобождение памяти (не обязательно, так как программа

    завершается). */

 munmap(file_memory, FILE_LENGTH);

 return 0;

}

Программа mmap-read читает число из файла, а затем удваивает его и записывает обратно в файл. Сначала файл открывается для чтения/записи. Поскольку предполагается, что файл содержит число, проверка с помощью функции lseek(), как в предыдущей программе, не требуется. Чтение содержимого памяти и его анализ выполняет функция lseek(). Функция sprintf() форматирует число и записывает его в память.

Ниже показан пример запуска обеих программ. Им на вход передается файл /tmp/integer-file.

% ./mmap-write /tmp/integer-file

% cat /tmp/integer-file

42

% ./mmap-read /tmp/integer-file

value: 42

% cat /tmp/integer-file

84

Обратите внимание: значение 42 оказалось записано в файл на диске, хотя функция write() не вызывалась. Последующее чтение файла осуществлялось без функции read(). Целое число записывалось в файл и извлекалось из него в текстовом виде (с помощью функций sprintf() и sscanf()). Это сделано исключительно в демонстрационных целях. В действительности отображаемый файл может содержать не только текст, но и двоичные данные.