Общая идея ввода-вывода с отображением в память заключается в том, что вы сообщаете операционной системе (ОС) , какой файл вам нужен, и он (после выполнения некоторой работы по настройке) сообщает вам где этот файл сейчас находится в памяти.
Как только этот контракт будет выполнен, вы сможете копировать вещи в эту память и из нее любым удобным для вас способом (например, с memcpy
),и он будет волшебным образом обрабатывать ввод-вывод для вас.
Подробно зависит от того, какую ОС вы используете, поскольку стандарт ISO C не определяет это поведение - поэтому он зависит от ОС.
Например, Windows использует парадигму сопоставления файлов, показанную здесь , в то время как Linux использует mmap
, чтобы позволить подвергнуть файл, который вы уже открыли, отображению памяти (через его файлдескриптор).
В качестве примера, эта программа для Linux, несколько объемная из-за проверки ошибок и отчетов о ходе выполнения, отображает в памяти файл file.txt
и выводит его содержимое:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
// Helper function to minimise error code in main.
static int clean(
int retVal, // value to return.
char *err, // error/NULL, allows optional %s for strerror(errno).
int fd, // fd/-1 to close.
void *filMem, // memory/NULL to unmap.
off_t sz, // size if unmapping.
void *locMem // memory/NULL to free.
) {
if (err) printf (err, strerror(errno));
if (locMem) free(locMem);
if (filMem) munmap(filMem, sz);
if (fd >= 0) close(fd);
return retVal;
}
int main(void) {
int fd = open("file.txt", O_RDONLY);
if (fd < 0) return clean(-1, "Can't open: %s\n", -1, NULL, 0, NULL);
printf("File opened okay, fd = %d.\n", fd);
off_t sz = lseek(fd, 0, SEEK_END);
if (sz == (off_t) -1) return clean(-1, "Can't seek: %s\n", fd, NULL, 0, NULL);
printf("File size is %ld.\n", sz);
void *fileArea = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
if (! fileArea) return clean(-1, "Can't map: %s\n", fd, NULL, 0, NULL);
printf("File mapped to address %p.\n", fileArea);
char *localArea = calloc(1, sz + 1);
if (! localArea) return clean(-1, "Can't allocate\n", fd, fileArea, sz, NULL);
memcpy(localArea, fileArea, sz);
printf("Data copied to %p, result is [\n%s]\n", localArea, localArea);
return clean(0, NULL, fd, fileArea, sz, localArea);
}
Запуск этого на моей локальной системествол, результаты можно увидеть из следующего стенограммы:
pax$ cat file.txt
...This is the input file content.
pax$ ./testprog
File opened okay, fd = 3.
File size is 35.
File mapped to address 0x7f868a93b000.
Data copied to 0x1756420, result is [
...This is the input file content.
]