mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数,所以使用mmap的效率是比,read, write的效率更高的
#include
void* mmap(void addr, size_t length, int prot, int flags, int fd, off_t offset);
若映射成功则返回映射区的内存起始地址, 否则返回 MAP_FAILED(-1)
start 指向欲对应的内存起始地址, 通常设为 NULL, 代表让系统自动选定地址, 对应成功后该地址会返回. 参数
length 代表将文件中多大的部分对应到内存.
prot 代表映射区域的保护方式,有:
PROT_EXEC 映射区域可被执行
PROT_READ 映射区域可被读取
PROT_WRITE 映射区域可被写入
PROT_NONE 映射区域不能存取
flags 影响映射区域的各种特性,调用 mmap() 时必须要指定 MAP_SHARED 或 MAP_PRIVATE。
MAP_FIXED:如果start所指地址无法成功建立映射,则放弃映射,不对地址做修正。
MAP_SHARED:对映射区域的写入数据会复制回文件内,且允许其他映射该文件的进程共享。
MAP_PRIVATE:对映射区域的写入操作会产生一个映射文件的拷贝,对此区域作的任何修改都不会写回原来的文件。
MAP_ANONYMOUS:建立匿名映射。此时会忽略参数fd,不涉及文件,且映射区域无法和其他进程共享。
MAP_DENYWRITE:只允许对映射区域的写入操作,其他对文件直接写入的操作将被拒绝。
MAP_LOCKED:将映射区域锁定,则该区域不会被置换(swap)。
fd 要映射到该内存区域的文件描述符,若使用匿名映射则会被设为 -1。
offset 文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍
打开文件
获取描述符
读取文件
关闭文件
使用内存映射方式读取文件文件? read_mmap.c
使用内存映射方式写入数据到文件中? read_mmap2.c
使用内存映射方式编写一个拷贝文件的代码read_mmap3.c
第一个例子
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char**argv){
int fd; //文件描述符
/**
* 打开文件
*/
if((fd = open(argv[1], O_RDWR)) < 0){
perror("open file error!!");
exit(-1);
}
/**
*让文件描述符,取得文件信息(获取大小信息)
*/
struct stat sb;
if(fstat(fd, &sb) < 0){
perror("Get file stat error!!");
exit(-1);
}
/**
*mmap映射
*/
char *start;
if((start = mmap(
NULL,
sb.st_size,
PROT_READ,
MAP_PRIVATE,
fd,
0)) == MAP_FAILED){
perror("MMAP ERROR!!");
exit(-1);
}
printf("文件信息:\n%s", start);
close(-1);
}
第二个例子
#include
#include
#include
#include
#include
#include
#include
#include
/*
char* MyStrcat(char *buf1, char *buf2)
{
char *temp = buf1; //指针temp指向des字符串内存地址
while (*buf1 != '\0'){ //如果temp指针没有遇见'\0'
buf1++;
} //temp++
while ((*buf1++ = *buf2++) != '\0'); //实现循环拷贝,当src为'\0'时结束
return temp; //返回des值
}*/
int main(int argc, char**argv){
int fd; //文件描述符
/**
* 打开文件
*/
if((fd = open(argv[1], O_RDWR)) < 0){
perror("open file error!!");
exit(-1);
}
/**
*让文件描述符,取得文件信息(获取大小信息)
*/
struct stat sb;
if(fstat(fd, &sb) < 0){
perror("Get file stat error!!");
exit(-1);
}
/**
*mmap映射
*/
char *start;
if((start = (char*)mmap(
NULL,
sb.st_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0)) == MAP_FAILED){
perror("MMAP ERROR!!");
exit(-1);
}
close(fd);
/**
*添加数据同步到磁盘文件(覆盖)
*/
char *buffer = "你可以滚了!";
int buf_len = strlen(buffer);
memcpy(start, buffer, buf_len);
munmap((void*)start, buf_len);
return 0;
}
例子三:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
void mmap_copy(int buf1_fd, size_t buf1_len, int buf2_fd);
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("path error");
exit(-1);
}
int buf1_fd;
int buf2_fd;
if ((buf1_fd = open(argv[1], O_RDONLY)) < 0){
printf("file1 open error!\n");
exit(-1);
}
if ((buf2_fd = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) {
printf("file2 open error! \n");
exit(-1);
}
struct stat sb;
fstat(buf1_fd, &sb); // 获取文件信息
truncate(argv[2], sb.st_size); // 设置文件大小
mmap_copy(buf1_fd, sb.st_size, buf2_fd);
start
close(buf1_fd);
close(buf2_fd);
return 0;
}
void mmap_copy(int buf1_fd, size_t buf1_len, int buf2_fd)
{
void *start1, *start2;
start1 = mmap(NULL, buf1_len, PROT_READ, MAP_PRIVATE, buf1_fd, 0);
start2 = mmap(NULL, buf1_len, PROT_WRITE | PROT_READ, MAP_SHARED, buf2_fd, 0);
if ((start1 < 0) && (start2 < 0)) {
printf("mmap error" );
exit(-1);
}
memcpy(start2, start1, buf1_len); // 实现拷贝
munmap(start1, buf1_len);
munmap(start2, buf1_len);
}