文件I/O-mmap

定义

参数



注意事项


文件与内存映射


// 修改文件内存映射
#include <stdio.h>
#include <sys/mman.h>   // mmap
#include <sys/stat.h>   // open
#include <sys/types.h>  // open
#include <fcntl.h>      // open
#include <unistd.h>     // lseek,write
#include <string.h>     // memcpy


int main(int argc, char *argv[]) {
    int fd;
    char *mapped_mem, *p;
    int flength = 1024;
    //void * start_addr = 0;

    fd = open(argv[1], O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
    flength = lseek(fd, 1, SEEK_END);
    write(fd, "\0", 1);
    lseek(fd, 0, SEEK_SET);
    mapped_mem = (char *)mmap(  NULL,                   // 系统自己决定映射区起始地址 
                                flength,                // 映射区数据长度
                                PROT_READ,              // 映射区保护方式
                                MAP_PRIVATE,            // 共享方式
                                fd,
                                0);
    /*使用映射区域*/
    printf("%s\n", mapped_mem);
    close(fd);
    munmap(mapped_mem, flength);       // 删除内存映射
    return 0;
}

修改文件的内存映像

#include <stdio.h>
#include <sys/mman.h>   // mmap
#include <sys/stat.h>   // open
#include <sys/types.h>  // open
#include <fcntl.h>      // open
#include <unistd.h>     // lseek,write
#include <string.h>     // memcpy


int main(int argc, char *argv[]) {
    int fd;
    char *mapped_mem, *p;
    int flength = 1024;

    fd = open(argv[1], O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
    flength = lseek(fd, 1, SEEK_END);
    write(fd, "\0", 1);
    lseek(fd, 0, SEEK_SET);
    mapped_mem = (char *)mmap(  NULL,                   // 系统自己决定映射区起始地址 
                                flength,                // 映射区数据长度
                                PROT_READ | PROT_WRITE, // 映射区保护方式
                                MAP_SHARED,             // 共享方式
                                fd,
                                0);
    /*使用映射区域*/
    printf("%s\n", mapped_mem);

    while ((p = strstr(mapped_mem, "ass"))) {
        memcpy(p, "123", 3);
        p += 3;
    }
    close(fd);
    munmap(mapped_mem, flength);       // 删除内存映射
    return 0;
}

mmap用法示例(1)

  • 下面代码的功能: 创建一个新文件,设置文件大小,使用mmap函数映射文件地址出来,对地址直接拷贝数据进入,再取消映射。 这时再打开文件,数据已经存放到到文件中了。演示通过mmap映射文件地址方式读写文件。
    https://juejin.cn/post/7058533534503272462
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

#define MAX 1024


int main(int argc, char *argv[])
{
    // 参数初始化
    int fd;

    // 配置参数
    if (argc != 2)
    {
        printf("usage:./exe filename\n");
        exit(EXIT_FAILURE);     // 包含的头文件,<stdlib.h>
    }

    // 创建文件
    // #define fileName file.txt
    //char fileName[MAX];
    //strcpy(fileName, (const)argv[1]);
    mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;    // S_IRWXU;  
    fd = open(argv[1], O_CREAT | O_RDWR, mode);   // O_EXCL如果文件存在则报错
    if (fd == -1)
    {
        perror("Error open func.\n");
        exit(EXIT_FAILURE);
    }

    // 设置文件大小
    ftruncate(fd, MAX); // fd文件大小修改为指定大小
    
    // 获取文件大小
    struct stat st;
    fstat(fd, &st);
    printf("%s size is %d Byte.\n", argv[1], st.st_size);

    // 映射文件到内存空间
    unsigned char * mem_p = NULL;
    mem_p = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (mem_p == NULL)
    {
        perror("Error mmap func.\n");
        close(fd);
        exit(EXIT_FAILURE);
    }

    // 关闭文件
    close(fd);

    // 实现文件读写
    strcpy(mem_p, "mmap func test.\n");

    // 打印文件内容
    printf("mem_p = %s\n", mem_p);

    // 改为大小字母
    for (int i = 0; i < st.st_size; i++)
    {
        mem_p[i] = toupper(mem_p[i]);
        putchar(mem_p[i]);
    }
    
    // 取消映射
    if (munmap(mem_p, st.st_size) == -1)
    {
        perror("Error munmap func.\n");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

多线程并发拷贝数据

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

#define FORK_NUM 4

/*
多进程并发拷贝大文件
*/
int main(int argc, char * argv[])
{
    // 参数处理
    if (argc != 3)
    {
        printf("usage:./exe <a> <b>\n");
        exit(EXIT_FAILURE);
    }

    // 打开源文件
    int src_fd = open(argv[1], O_RDWR);
    if (src_fd == -1)
    {
        perror("Error open func.\n");
        exit(EXIT_FAILURE);
    }

    // 创建新文件
    int new_fd = open(argv[2], O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    if (new_fd == -1)
    {
        perror("Error open func new.\n");
        exit(EXIT_FAILURE);
    }

    // 获取源文件大小,设置新文件大小
    struct stat src_st;
    fstat(src_fd, &src_st);
    printf("src_fd size is:%d.\n", src_st.st_size);
    ftruncate(new_fd, src_st.st_size);

    // 映射源文件到内存空间
    unsigned char * src_p;
    src_p = mmap(NULL, src_st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, src_fd, 0);
    if (src_p == NULL)
    {
        close(src_fd);
        perror("Error mmap func.\n");
        exit(EXIT_FAILURE);
    }

    unsigned char * new_p;
    new_p = mmap(NULL, src_st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, new_fd, 0);
    if (new_p == NULL)
    {
        close(new_fd);
        perror("Error mmap func.\n");
        exit(EXIT_FAILURE);
    }

    // 关闭文件
    close(new_fd);
    close(src_fd);

    // 计算子进程和父进程拷贝文件字节大小
    int cp_size = 0;
    int main_size = 0;
    cp_size = src_st.st_size / FORK_NUM;
    main_size = src_st.st_size % FORK_NUM;

    // 创建子进程
    int i;
    for (i = 0; i < FORK_NUM; i++)
    {
        if (fork() == 0)
            break;
    }

    // 子进程完成文件的拷贝
    if (i < FORK_NUM)   // 子进程
    {
        memcpy(new_p + i * cp_size, src_p + i * cp_size, cp_size);
        munmap(new_p, src_st.st_size);
        munmap(src_p, src_st.st_size);
    }
    else        // 父进程
    {
        memcpy(new_p + i * cp_size, src_p + i * cp_size, main_size);
        munmap(new_p, src_st.st_size);
        munmap(src_p, src_st.st_size);

        pid_t pid;
        while (1)
        {
            pid = wait(NULL);
            if (pid == -1)
                break;
            printf("%d thread over.\n", pid);
        }
        printf("%d main thread over.\n", pid);
    }
    exit(EXIT_SUCCESS);
}

posted @ 2022-04-30 20:22  starc的miao  阅读(64)  评论(0)    收藏  举报