mmap映射实战举例

mmap映射实战举例

需求:在Linux环境下,需要打开一个文件,然后映射到内存中,接着在特定的地址偏移处写入内容,并且在此之前需要清空该位置的内容并填充为ff,写完再做校验。

步骤:

  1. 打开文件:使用open()函数打开文件。
  2. 内存映射:使用mmap()函数将文件映射到内存中。
  3. 清空并填充:使用指针操作和memset()函数来清空并填充特定区域。
  4. 写入内容:将需要写入的内容通过指针写入到映射的内存区域。
  5. 同步内存映射:使用msync()函数确保内存中的数据写回到文件。
  6. 校验内容:使用memcmp()函数比较写入内容是否正确。
  7. 取消映射:使用munmap()函数取消映射。
  8. 关闭文件:使用close()函数关闭文件。
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    // 打开文件
    int fd = open("wuyanzu.txt", O_RDWR);
    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    // 获取文件大小
    struct stat sb;
    if (fstat(fd, &sb) == -1) {
        perror("fstat");
        exit(EXIT_FAILURE);
    }

    // 内存映射文件
    void *mapped_area = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (mapped_area == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    // 指定的偏移量和大小
    off_t offset = 1024; // 举例的偏移量
    size_t size_to_fill = 512; // 举例的填充大小

    // 清空并填充为ff
    memset((char *)mapped_area + offset, 0xff, size_to_fill);

    // 写入内容到指定偏移量的位置
    // 假设我们有一个字符数组作为示例内容
    char content[] = "Hello, World!";
    memcpy((char *)mapped_area + offset, content, sizeof(content));

    // 将内存中的数据同步到磁盘上
    if (msync(mapped_area, sb.st_size, MS_SYNC) == -1) {
        perror("msync");
        munmap(mapped_area, sb.st_size);
        exit(EXIT_FAILURE);
    }
	
    //校验
    if(memcmp((char *)mapped_area + offset, content, sizeof(content)) != 0)
    {
        perror("memcmp");
        munmap(mapped_area, sb.st_size);
        exit(EXIT_FAILURE);
    }
    
    // 取消映射
    if (munmap(mapped_area, sb.st_size) == -1) {
        perror("munmap");
        exit(EXIT_FAILURE);
    }

    // 关闭文件
    if (close(fd) == -1) {
        perror("close");
        exit(EXIT_FAILURE);
    }

    return 0;
}
### mmap 函数的使用方法 `mmap` 是一种用于创建内存映射文件区域的系统调用,在 POSIX 兼容的操作系统(如 Linux 和 macOS)中广泛使用。它允许进程将文件或其他对象映射到其地址空间,从而可以通过操作内存来读写文件内容。 以下是 `mmap` 的基本语法及其参数说明: #### 基本语法 ```c void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); ``` - **`addr`**: 请求的起始地址。通常设置为 `NULL`,让操作系统决定合适的地址[^1]。 - **`length`**: 映射区域的长度(字节单位)。必须是非零值[^2]。 - **`prot`**: 指定访问权限,可以是以下标志的组合: - `PROT_READ`: 可读。 - `PROT_WRITE`: 可写。 - `PROT_EXEC`: 可执行。 - `PROT_NONE`: 不可访问。 - **`flags`**: 控制行为的标志位,常见选项有: - `MAP_SHARED`: 修改会反映回文件。 - `MAP_PRIVATE`: 创建私有的副本,修改不会影响原文件。 - **`fd`**: 文件描述符,表示要映射的文件。如果不需要关联文件,则应指定特殊值(如 `-1`),并配合其他标志使用。 - **`offset`**: 文件中的偏移量,必须是对页大小取整的结果[^3]。 成功返回指向已映射区间的指针;失败则返回 `(void *) -1` 并设置 errno 来指示错误原因。 --- ### 示代码 下面是一个简单的 C 程序,展示如何利用 `mmap` 将一个文件的内容映射到内存中,并对其进行读写操作。 ```c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> int main() { const char *filename = "example.txt"; int fd = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd == -1) { perror("open"); exit(EXIT_FAILURE); } // 设置文件大小以便有足够的数据供映射 ftruncate(fd, 4096); void *mapped_region = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mapped_region == MAP_FAILED) { perror("mmap"); close(fd); exit(EXIT_FAILURE); } // 向映射区域写入一些数据 snprintf(mapped_region, 4096, "Hello from mmap!"); printf("Mapped content: %s\n", (char*) mapped_region); munmap(mapped_region, 4096); // 解除映射关系 close(fd); // 关闭文件描述符 return EXIT_SUCCESS; } ``` 此程序完成如下功能: 1. 打开名为 `"example.txt"` 的文件或者新建该文件; 2. 使用 `ftruncate()` 调整文件尺寸至至少一页(这里设定了4KB),确保有足够的空间被映射; 3. 利用 `mmap()` 把这段范围内的文件内容加载进内存; 4. 对这个新建立起来的虚拟存储器位置进行字符串赋值以及打印验证; 5. 清理工作包括解除映射(`munmap`)和关闭文件句柄(close). --- ### 注意事项 当不再需要某个由 `mmap` 返回的内存区间时,应该显式地通过调用 `munmap(addr,length)` 来释放资源。否则可能导致未定义的行为发生,比如尝再次映射同一段地址可能会失败等问题出现[^4]. 另外需要注意的是,尽管上面子演示了共享模式下的情况 (`MAP_SHARED`), 如果希望更改只存在于当前进程中而不同步更新原始文件的话,则需改用复制方式即设定成 `MAP_PRIVATE`. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值