Linux文件编程5-文件的内存映射(mmap)

文件的内存映射

为什么要将文件映射到内存?

频繁地读取和写入文件十分耗时,如果能将文件加载到内存中,则读取和写入的主体就变成了程序和内存而不是程序和文件,大大减小时间开销。另外,将文件映射到内存中并由多个进程访问,能够实现进程之间共享内存。

函数和主要参数

#include <sys/mman.h>
/**
 * @param start     映射内存的起始地址,通常设为NULL或0,表示由系统自动分配
 * @param length    写入数据的长度
 * @param prot      映射区的保护方式
 * @param flags     映射区类型以及是否共享
 * @param fd        文件描述符
 * @param offset    映射数据在文件中的起点 
 */
void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset);
prot意义
PROT_EXEC映射区可被执行
PROT_READ映射区可被读取
PROT_WRITE映射区可被写入
PROT_NONE映射区不可访问
flags意义
MAP_FIXED在指定参数start时使用,若无法映射到start区域,则映射失败
MAP_SHARED共享映射区域,对映射区域写入将会写入到原文件中
MAP_PRIVATE为进程创建一个独享映射,修改映射区域不会保存到原文件中
MAP_ANONYMOUS建立匿名映射。映射区不与任何文件关联,无法共享
MAP_DENYWRITE对文件的写入操作将被禁止
MAP_LOCKED锁定映射区,防止映射区的内存被交换

flag必须为MAP_SHAREDMAP_PRIVATE二者之一,其他类型需与此二者搭配使用。

通过内存映射读取文件

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char** argv){
    int fd = open(argv[1], O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
    char* mappedMem, * p;
    int flength = 1024;
    void* startAddr = 0;

    if(fd>0){
        flength = lseek(fd, 1, SEEK_END);
        write(fd, "\0", 1);
        lseek(fd, 0, SEEK_SET);
        mappedMem = (char*)mmap(startAddr, flength, PROT_READ, MAP_PRIVATE, fd, 0);

        printf("%s\n", mappedMem);

        close(fd);
        munmap(mappedMem, flength);
    }
    return 0;
}

I have an apple.

先向文件中追加了一个字符’\0’,来满足printf打印所需。在mmap函数中,我们设置prot参数为PROT_READ,表示这块内存映射可以读取;设置flags参数为MAP_PRIVATE,表示进程独享该内存映射,并且不将内存映射中的修改写入原文件(时间上此处由于prot参数的问题也无法修改)。

执行后成功将文件内容打印。

通过内存映射修改文件

此处只需要修改通过内存映射读取文件中的prot和flag参数,就可以让我们具有权限去实现修改内存映射,并将内存映射保存到原文件中。

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>


int main(int argc, char** argv){
    int fd = open(argv[1], O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
    char* mappedMem, * p;
    int flength = 1024;
    void* startAddr = 0;

    if(fd>0){
        flength = lseek(fd, 1, SEEK_END);
        write(fd, "\0", 1);
        lseek(fd, 0, SEEK_SET);
        mappedMem = (char*)mmap(startAddr, flength, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

        printf("%s\n", mappedMem);

        p = strstr(mappedMem, "apple");
        memcpy(p, "linux", 5);

        close(fd);
        munmap(mappedMem, flength);
    }
    return 0;
}

I have an apple.

之后在终端中执行:

$ cat myFile.txt

I have an linux.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值