8.1 存储映射介绍

8.1.1 概念

  存储映射是一个磁盘文件与存储空间的一个缓存相映射,对缓存数据的读写就相应的完成了文件的读写。

  

  文件操作部分映射到虚拟内存的一块区域,我们对虚拟内存映射的那块区域进行读写操作,读写之后,那块区域自动同步到文件当中。

  4G空间分布:

  

  共享内存映射区就是文件映射到的内存区。

8.1.2 mmap---建立内存映射

 #include <unistd.h>
#include <sys/mman.h>
//mmap(建立内存映射)
void *mmap(void *start, size_t length, int prot, int flags, int fd,off_t offsize);
  • 函数说明

    • mmap()用来将某个文件内容映射到内存中,对该内存区域的存取即是直接对该文件内容的读写。
    • 作用就是 使一个磁盘文件与存储空间中的一个缓存相映射
    • mmap 函数从缓存中获取数据,就相当于读文件中的相应字节。与其类似,将数据存入缓存,则相应字节就自动地写入文件。这样,就可以再不使用 read 和 write 的情况下执行 I/O
    • 子进程继承父进程的映射
  • 参数说明:
    • @start:指向欲对应的内存起始地址,通常设为NULL或0,代表让系统自动选定地址,对应成功后该地址会返回。
    • @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 内存不足。

8.1.3 munmap---解除内存映射

 #include <unistd.h>
#include <sys/mman.h>
//munmap(解除内存映射)
int munmap(void *start,size_t length);
  • 函数说明

    • munmap() 用来取消参数 start 所指的映射内存起始地址,参数length 则是欲取消的内存大小。
    • 当进程结束或利用 exec 相关函数来执行其他程序时,映射内存会自动解除,但关闭对应的文件描述符时不会解除映射。
  • 返回值
    • 如果解除映射成功则返回0,否则返回-1,错误原因存于 errno 中
  • 错误代码
    • EINVAL     参数 start或length 不合法。

8.2 例子

(1)写字符

  通过存储映射向文件中写入若干个字符。(文件中必须开辟空间供存储映射区同步,就相当于在写入的区域做一块空洞文件,然后将空洞文件映射到存储映射区)

 #include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h> int main(int argc, const char *argv[])
{
if(argc < ) {
printf("usage: %s file\n", argv[]);
exit();
} int fd = open(argv[], O_RDWR);
if(fd < ){
perror("open error");
exit();
} //在19个字节处写入一个0
lseek(fd, , SEEK_END);
write(fd, "", ); char *addr;
//进行存储映射
addr = mmap(, , PROT_WRITE, MAP_SHARED, fd, );
if(addr < ) {
perror("mmap error");
exit();
} //修改存储映射区的内容
int i;
for(i = ; i < ; i++)
{
*(addr + i) = 'A' + i;
}
printf("write success\n"); //解除映射
munmap(addr, ); close(fd); return ;
}

  程序运行结果:

  

(2)文件的拷贝

 #include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h> int main(int argc, const char *argv[])
{
if(argc < ) {
printf("usage: %s srcfile destfile\n", argv[]);
exit();
} int src_fd;
int dest_fd; if((src_fd = open(argv[], O_RDONLY)) < ) {
perror("open error");
exit();
} if((dest_fd = open(argv[], O_RDWR | O_CREAT | O_TRUNC, )) < ) {
perror("open error");
exit();
} // 定位到文件尾部,返回一个偏移量,反应文件长度
long len = lseek(src_fd, , SEEK_END);
printf("len: %ld\n", len); // 在文件开始处跳过 len-1 个字节
lseek(dest_fd, len-, SEEK_SET);
write(dest_fd, "", ); //创建了目标文件的空洞文件 char *src_map = mmap(, len, PROT_READ, MAP_SHARED, src_fd, );
if(src_map < ) {
perror("mmap error");
exit();
} char *dest_map = mmap(, len, PROT_WRITE, MAP_SHARED, dest_fd, );
if(dest_map < ) {
perror("mmap error");
exit();
} //存储映射区的复制并同步到文件中
memcpy(dest_map, src_map, len);
munmap(src_map, );
munmap(dest_map, ); close(src_fd);
close(dest_fd); return ;
}

  运行结果:

  

  

八、文件IO——存储映射的更多相关文章

  1. (代码篇)从基础文件IO说起虚拟内存,内存文件映射,零拷贝

    上一篇讲解了基础文件IO的理论发展,这里结合java看看各项理论的具体实现. 传统IO-intsmaze 传统文件IO操作的基础代码如下: FileInputStream in = new FileI ...

  2. (理论篇)从基础文件IO说起虚拟内存,内存文件映射,零拷贝

    为了快速构建项目,使用高性能框架是我的职责,但若不去深究底层的细节会让我失去对技术的热爱. 探究的过程是痛苦并激动的,痛苦在于完全理解甚至要十天半月甚至没有机会去应用,激动在于技术的相同性,新的框架不 ...

  3. 第3章 文件I/O(7)_高级文件操作:存储映射

    8. 高级文件操作:存储映射 (1)概念: 存储映射是一个磁盘文件与存储空间的一个缓存相映射,对缓存数据的读写就相应的完成了文件的读写. (2)mmap和munmap函数 头文件 #include&l ...

  4. Android学习笔记--存储方案(SharedPreference、文件IO)

    1. SharedPreference SharedPreference可以很容易的保存key-value对,通常用于保存配置信息.保存的步骤 1. 获得SharedPreferences对象 (最后 ...

  5. ElasticSearch入门 第八篇:存储

    这是ElasticSearch 2.4 版本系列的第八篇: ElasticSearch入门 第一篇:Windows下安装ElasticSearch ElasticSearch入门 第二篇:集群配置 E ...

  6. linux中的 IO端口映射和IO内存映射

    参考自:http://blog.csdn.net/zyhorse2010/article/details/6590488 CPU地址空间 (一)地址的概念 1)物理地址:CPU地址总线传来的地址,由硬 ...

  7. 文件IO大纲

    文件流与文件描述符的区别 a) 任何进程在运行时都默认打开3个流对象,(stdin, stdout, stderr)它们都有对应的文件描述符,其文件描述符分别为0,1,2,以后打开的文件描述符的值一般 ...

  8. 存储映射--mmap

    存储映射 使一个磁盘文件与存储空间中的一个缓冲区相映射. 当从缓冲区中取数据,就相当于读文件中的相应字节. 将数据存入缓冲区,则相应的字节就自动写入文件. 使用这种方法,首先应通知内核,将一个指定文件 ...

  9. linux 中的页缓存和文件 IO

    本文所述是针对 linux 引入了虚拟内存管理机制以后所涉及的知识点.linux 中页缓存的本质就是对于磁盘中的部分数据在内存中保留一定的副本,使得应用程序能够快速的读取到磁盘中相应的数据,并实现不同 ...

随机推荐

  1. cf1073D Berland Fair (二分答案+树状数组)

    用一个树状数组维护前缀和,每次我二分地找一个位置,使得我能一路买过去 但这个买不了 那以后肯定也都买不了了,就把它改成0,再从头二分地找下一个位置,直到这一圈我可以跑下来 然后就看跑这一圈要花多少钱. ...

  2. can物理信号-----------显性和隐性

    can信号使用差分电压传送,两条信号线被称为CAN_H和CAN_L.静态时均是2.5v左右,此时状态表示为逻辑“1”,也可以叫做隐性.用CAN_H比CAN_L高表示逻辑“0”,称为显性,此时通常电压值 ...

  3. 买卖股票的最佳时机II

    题目描述 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润. 注意你不能在买入股票前卖出股 ...

  4. saltstack常用命令

    Salt通过公钥加密和认证minions.想要让minion从master端接受命令,minions的密钥需要被master接受 salt-key -L #列出master上的密钥; salt-key ...

  5. c# WebApi之解决跨域问题:Cors

    什么是跨域问题 出于安全考虑,浏览器会限制脚本中发起的跨站请求,浏览器要求JavaScript或Cookie只能访问同域下的内容.由于这个原因,我们不同站点之间的数据访问会被拒绝. Cors解决跨域问 ...

  6. 跟我一起写一个hello-world react组件并发布到npm

    第一步:初始化我们的配置 $ mkdir react-hello-world $ cd react-hello-world/ $ npm init -y 修改我们的package.json文件 //p ...

  7. Redis:默认配置文件redis.conf详解

    转: Redis:默认配置文件redis.conf详解 # Redis配置文件样例 # Note on units: when memory size is needed, it is possibl ...

  8. 使用webdriver+urllib爬取网页数据(模拟登陆,过验证码)

    urilib是python的标准库,当我们使用Python爬取网页数据时,往往用的是urllib模块,通过调用urllib模块的urlopen(url)方法返回网页对象,并使用read()方法获得ur ...

  9. /bin/bash^M:损坏的解释器: 没有那个文件或目录

    由于在Windows下换行是\n\r,在Linux下打开多了\r,所以需要删除.删除命令 :sed -i 's/\r$//' filename -i插入 s替代模式 \r$表示任何以\r结束的字符 整 ...

  10. log4net 开启内部调试

    大家都在用LOG4NET,但这是封装好的,在有时我们找不到原因时会想到是不是发生在里面,比如,配置好了日志记录到数据库(Mysql.Oracle.Sql Server)等,但就是记录不上,又找不到原因 ...