Itay Goldfaden
Itay Goldfaden

Reputation: 21

memory mapped read from a fie I/O C/C++

I'm new in the area of memory mapped and I was wondering if there is any way I can read a text file using memory mapped to a string. I don't really know how to start to write the code.

Upvotes: 2

Views: 2307

Answers (1)

paxdiablo
paxdiablo

Reputation: 882316

The general idea with memory mapped I/O is that you tell the operating system (OS) what file you want, and it (after doing some amount of set-up work) tells you where that file now is in memory.

Once that contract is performed, you should be able to copy things to and from that memory in any way you wish (such as with memcpy), and it will magically handle the I/O for you.

Detail depends on which OS you're using since the ISO C standard doesn't specify this behaviour - it's therefore OS-specific.

For example, Windows uses a file mapping paradigm shown here, while Linux uses mmap to allow you to subject a file you've already opened to memory mapping (via its file descriptor).

By way of example, this Linux program, a little voluminous due mainly to its error checking and progress reports, memory maps the file.txt file and outputs its content:

#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);
}

Running that on my local system, the results can be seen from the following transcript:

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.
]

Upvotes: 5

Related Questions