内存映射I/O
来源:互联网 发布:乐视mac码怎么查 编辑:程序博客网 时间:2024/04/27 19:06
1.概念
将一个文件与内存中的某一个缓冲区建立一种映射关系。用户对缓冲区进行读写就相当于对相应的文件进行读写。
2.创建内存映射
#include <sys/mman.h>
定义函数 void *mmap(void *start,size_t length,int prot,int flags,intfd,off_t offsize);
函数说明mmap()用来将某个文件内容映射到内存中,对该内存区域的存取即是直接对该文件内容的读写。参数start指向欲对应的内存起始地址,通常设为NULL,代表让系统自动选定地址,对应成功后该地址会返回。参数length代表将文件中多大的部分对应到内存。
参数 prot代表映射区域的保护方式有下列组合
PROT_EXEC 映射区域可被执行
PROT_READ 映射区域可被读取
PROT_WRITE 映射区域可被写入
PROT_NONE 映射区域不能存取
参数 flags会影响映射区域的各种特性
MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。
MAP_SHARED对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。
MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。
MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。
MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。
MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。
在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。参数fd为open()返回的文件描述词,代表欲映射到内存的文件。参数offset为文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。
返回值 若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno 中。
错误代码 EBADF 参数fd 不是有效的文件描述词EACCES 存取权限有误。如果是MAP_PRIVATE 情况下文件必须可读,使用MAP_SHARED则要有PROT_WRITE以及该文件要能写入。
EINVAL 参数start、length 或offset有一个不合法。
EAGAIN 文件被锁住,或是有太多内存被锁住。
ENOMEM 内存不足。
//nmap.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
int main(void)
{
int fd;
char *buf;
int i;
struct stat statbuf;
if(stat("test.txt", &statbuf) == -1){ /* 得到一个文件的状态信息,得到文件的大小 */
perror("fail to get stat");
exit(1);
}
fd = open("test.txt", O_RDONLY); /* 以只读方式打开文件 */
if(fd == -1){
perror("fail to open");
exit(1);
}
/* 建立一个内存映射,起始地址由系统为用户选择,并作为返回值返回
* 建立的映射区的大小为打开的文件的大小
* 访问权限为只读,属性为不会写到磁盘,防止对其进行写的误操作
*/
buf = (char *)mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if(buf == MAP_FAILED){
perror("fail to mmap");
exit(1);
}
i = 0;
while(i < statbuf.st_size){ /* 输出每一个字符,注意mmap函数不会添加’/0’结束符 */
printf("%c", buf[i]);
i++;
}
printf("/n");
if(munmap(buf, statbuf.st_size) == -1){ /* 撤销内存映射 */
perror("fail to munmap");
exit(1);
}
close(fd); /* 关闭文件 */
return 0;
}
3.撤销一个内存映射
#include<unistd.h>
#include<sys/mman.h>
定义函数 int munmap(void *start,size_t length);
函数说明 munmap()用来取消参数start所指的映射内存起始地址,参数length则是欲取消的内存大小。当进程结束或利用exec相关函数来执行其他程序时,映射内存会自动解除,但关闭对应的文件描述词时不会解除映射。
返回值 如果解除映射成功则返回0,否则返回-1,错误原因存于errno中。
错误代码EINVAL参数 start或length 不合法。
4.内存映射同步
保证对缓冲区进行的修改回反映到磁盘中。
#include <sys/mman.h>
int msync(void * addr,sizt_t len,int flags);
addr表示要写回磁盘的内存映射区,flags表示回写的标志。
msync 意义
MS_ASYNC 不等待页面写回磁盘,只是将修改过的页面放入内核的写出队列中,msync函数立即返回
MS_SYNC 等待页面写回磁盘,知道页面写磁盘完毕,再返回
MS_INVALIDATE 丢弃指定范围的所有页面
5.更改内存映射的权限
#include <sys/mman.h>
int mprotect(void * addr,size_t len,int PROT);
addr是内存映射区的首地址,len是映射区的大小,PROT表示修改后的新权限。
//protect.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
/* SIGBUS信号的处理函数,输出一行提示信息 */
void sigbus_handler(int signo)
{
printf("permission denied/n");
}
int main(void)
{
int fd;
char *buf;
struct stat statbuf;
if(signal(SIGBUS, sigbus_handler) == SIG_ERR){ /* 设置SIGBUS的信号处理程序 */
perror("can’t set handler for SIGALRM");
exit(0);
}
if(stat("test.txt", &statbuf) == -1){ /* 得到一个文件的状态信息,得到文件的大小 */
perror("fail to get stat");
exit(1);
}
fd = open("test.txt", O_WRONLY); /* 以可写方式打开文件 */
if(fd == -1){
perror("fail to open");
exit(1);
}
/* 建立一个内存映射区,其访问权限为只读 */
buf = (char *)mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
if(buf == MAP_FAILED){
perror("fail to mmap");
exit(1);
}
printf("try to write/n");
strcpy(buf, "China/n"); /* 尝试写一个只读的映射区 */
/* 将映射区的访问权限改变为可读可写 */
if(mprotect(buf, statbuf.st_size, PROT_READ | PROT_WRITE) == -1){
perror("fail to alter permission");
exit(1);
}
printf("write again/n");
strcpy(buf, "China/n"); /* 再次写一个只读的映射区 */
if(munmap(buf, statbuf.st_size) == -1){ /* 撤销内存映射 */
perror("fail to munmap");
exit(1);
}
close(fd); /* 关闭文件 */
return 0;
}
- 内存映射I/O
- 内存映射文件 I/O
- linux I/O内存映射
- I/O内存资源映射
- I/O映射和内存映射
- I/O端口映射与内存映射
- 基于内存映射之I/O----NIO
- 内存映射文件-Java I/O系统
- I/O 和 内存映射文件
- iomem—I/O映射方式的I/O端口和内存映射方式的I/O端口
- iomem—I/O映射方式的I/O端口和内存映射方式的I/O端口
- ARM体系结构下面内存和i/o映射区别
- NIO之MappedByteBuffer内存映射文件I/O
- Java基础增强 : 新I/O中内存映射文件
- ARM体系结构下面内存和i/o映射区别
- java I/O系统(6)-内存映射文件
- ARM体系结构下面内存和i/o映射区别
- 存储映射I/O
- 开新站了
- #ifndef#define#endif的用法
- CEMAPI实战攻略(四)——发送短消息
- 面向对象设计原则二
- 网页打印代码
- 内存映射I/O
- 面向对象设计原则三
- 网站做得再好看,不做seo,不做优化的话,也只能做绣花枕头!!
- Cempi实战攻略(六)——如何截获到达的短消息
- 上班第一天学习svn 和 cvs
- Remoting中的方法回调
- 面向对象设计原则四
- labelmx电子监管码条码设计软件
- 用gdi+将内存位图文件保存为其它格式的图片