首页 > 系统相关 >在linux中使用内存映射(mmap)操作文件

在linux中使用内存映射(mmap)操作文件

时间:2023-06-12 10:03:38浏览次数:39  
标签:文件 映射 int mmap stu fd 内存 linux include


1,打开或创建文件,得到文件描述符,

2,将内存中的数据以一定的格式和顺序写入文件,或者将文件中的数据以一定的格式和顺序读入到内存;

3,关闭文件描述符;

下边是按照常规方式操作固定格式的文件的方法,包含读写两个示例;

1. #include <stdlib.h>
2. #include <stdio.h>
3. #include <unistd.h>
4. #include <fcntl.h>
5. #include <string.h>
6.  
    //写内存到文件 
   
7. struct student{
8. char name[ 
    20]; 
   
9. short
10. float
11. char
12. 
     }; 
   
13. int main()
14. 
     { 
   
15. struct student stu[5];
16. mode_t
17. 000); 
   
18. int fd=open( 
    "user.dat",O_RDWR|O_CREAT|O_EXCL, 
    00666); 
   
19. if(fd== 
    -1){ 
   
20. printf( 
    "open:%m\n"); 
   
21. 
     umask(mode); 
   
22. exit( 
    -1); 
   
23. 
     } 
   
24. printf( 
    "ok\n"); 
   
25. memset(stu, 
    0, 
    sizeof(stu)); 
   
26. int i= 
    0; 
   
27. for(;i< 
    5;i++){ 
   
28. memcpy(stu[i].name, 
    "tom", 
    strlen( 
    "tom")+ 
    1); 
   
29. 
     stu[i].age=i; 
   
30. 89.12f; 
   
31. 'm'; 
   
32. sizeof(stu[i])); 
   
33. 
     } 
   
34. 
     close(fd); 
   
35. 
     umask(mode); 
   
36. return 
    0; 
   
37. 
     } 
   
1. #include <stdio.h>
2. #include <stdlib.h>
3. #include <unistd.h>
4. #include <fcntl.h>
5. #include <string.h>
6.  
   
7. typedef 
    struct{
8. char name[ 
    20]; 
   
9. short
10. float
11. char
12. 
     }Student; 
   
13.  
    //读取文件到内存 
   
14. int main()
15. 
     { 
   
16. 5]; 
   
17. mode_t
18. 0000); 
   
19. int fd=open( 
    "user.dat",O_RDWR, 
    0666); 
   
20. if(fd== 
    -1){ 
   
21. printf( 
    "open:%m\n"); 
   
22. 
     umask(mode); 
   
23. exit( 
    -1); 
   
24. 
     } 
   
25. printf( 
    "open ok! can read;\n"); 
   
26. int i= 
    0; 
   
27. for(;i< 
    5;i++){ 
   
28. sizeof(stu[i])); 
   
29. 
     } 
   
30. 
     close(fd); 
   
31. 0; 
   
32. for(;i< 
    5;i++){ 
   
33. printf( 
    "stu[%d].name=%s\n",i,stu[i].name); 
   
34. printf( 
    "stu[%d].age=%d\n",i,stu[i].age); 
   
35. printf( 
    "stu[%d].sex=%c\n",i,stu[i].sex); 
   
36. printf( 
    "stu[%d].score=%f\n",i,stu[i].score); 
   
37. 
     } 
   
38. 
     umask(mode); 
   
39. return 
    0; 
   
40. 
     }

以上操作文件的方式只能操作小文件,如果文件很大,就无法一次载入内存操作,我们就需要用到内存映射技术来操作;具体实现如下:

1,首先打开文件,使用的函数原型如下:

int open(  //返回值:大于等于0代表操作成功,返回打开的文件描述符号,=-1,创建或者打开失败,失败可查阅errorno来获取具体错误信息
const char *pathname,   //要打开的文明名
int flags, //打开的方式,打开方式包括:O_RDONLY 只读方式 O_WRONLY 只写,O_RDWR读写,O_CREAT创建,O_EXCL文件如果存在,使用此标记,会返回错误
mode_t mode); //指定创建文件的权限,只对创建文件有效,对于打开无效;

2,获取文件大小

int fstat(int fd,//文件描述符号
struct stat*buf);//返回文件属性结构体
返回值:成功返回0;失败返回-1

3,把文件映射成虚拟内存

void *mmap(void *addr,  //从进程的那个地址开始映射,如果为NULL,由系统指定;
size_t length, //映射的地址空间的大小
int prot, //内存的保护模式
int flags,//映射模式 有匿名,私有,保护等标记 具体查询man手册;
int fd,  //如果为文件映射,则此处为文件的描述符号
off_t offset);//如果为文件映射,则此处代表定位到文件的那个位置,然后开始向后映射。
返回值:映射成功,返回首地址;

4,通过对内存的读写来实现对文件的读写

通常使用:memset 和memcpy来实现操作;

5,卸载映射

int munmap(void *addr,  //要卸载的内存的地址
size_t length);//内存的大小

6,关闭文件

int close(int fd);  //要关闭的文件描述符号  ,成功返回0,错误返回-1,错误参照errorno;

下边是读取文件的操作:

1. #include <stdio.h>
2. #include <stdlib.h>
3. #include <unistd.h>
4. #include <fcntl.h>
5. #include <sys/mman.h>
6. #include <sys/stat.h>
7. typedef struct{
8. char name[20];
9. short
10. float
11. char
12. }student;
13. int main()
14. {
15.   student *p,*pend;  
16. //打开文件描述符号
17. int
18. /*打开文件*/
19. "user.dat",O_RDWR);
20. if(fd==-1){//文件不存在
21. "user.dat",O_RDWR|O_CREAT,0666);
22. if(fd==-1){
23. printf("打开或创建文件失败:%m\n");
24. exit(-1);
25.         }
26.     }
27. //打开文件ok,可以进行下一步操作
28. printf("open ok!\n");  
29. //获取文件的大小,映射一块和文件大小一样的内存空间,如果文件比较大,可以分多次,一边处理一边映射;
30. struct stat st; //定义文件信息结构体
31. /*取得文件大小*/
32. int
33. if(r==-1){
34. printf("获取文件大小失败:%m\n");
35.       close(fd);
36. exit(-1);
37.   }
38. int
39. /*把文件映射成虚拟内存地址*/
40. NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);    
41. if(p==NULL || p==(void*)-1){
42. printf("映射失败:%m\n");
43.       close(fd);
44. exit(-1);
45.   }
46. /*定位到文件开始*/
47.   pend=p; 
48. /*通过内存读取记录*/
49. int i=0;
50. while(i<(len/sizeof(student)))
51.   {
52. printf("第%d个条\n",i);
53. printf("name=%s\n",p[i].name);
54. printf("age=%d\n",p[i].age);
55. printf("score=%f\n",p[i].score);
56. printf("sex=%c\n",p[i].sex);
57.     i++;
58.   }  
59. /*卸载映射*/
60.   munmap(p,len);
61. /*关闭文件*/
62.   close(fd);    
63. }

标签:文件,映射,int,mmap,stu,fd,内存,linux,include
From: https://blog.51cto.com/u_16081664/6459713

相关文章

  • 【操作系统】【硬件结构】磁盘比内存慢几万倍?存储器的层次结构?
    1  前言大家如果想自己组装电脑的话,肯定需要购买一个CPU,但是存储器方面的设备,分类比较多,那我们肯定不能只买一种存储器,比如你除了要买内存,还要买硬盘,而针对硬盘我们还可以选择是固态硬盘还是机械硬盘。相信大家都知道内存和硬盘都属于计算机的存储设备,断电后内存的数据是会丢......
  • C++面试八股文:如何在堆上和栈上分配一块内存?
    C++面试八股文:如何在堆上和栈上分配一块内存?某日二师兄参加XXX科技公司的C++工程师开发岗位6面:面试官:如何在堆上申请一块内存?二师兄:常用的方法有malloc,new等。面试官:两者有什么区别?二师兄:malloc是向操作系统申请一块内存,这块内存没有经过初始化,通常需要使用memset手......
  • 狂飙Linux平台,软件部署大全
    ......
  • 内存池(MemPool)技术详解
    概述内存池(MemPool)技术备受推崇。我用google搜索了下,没有找到比较详细的原理性的文章,故此补充一个。另外,补充了boost::pool组件与经典MemPool的差异。同时也描述了MemPool在sgi-stl/stlport中的运用。经典的内存池技术经典的内存池(MemPool)技术,是一种用于分配大量大小相同的小对象的......
  • linux下多种yum repo 创建
    一、使用本地文件1>拷贝镜像文件至mnt目录ISO镜像:CentOS-7-x86_64-DVD-1810mount/dev/sr0/media/cp-r/media/mnt/2>创建local.repo[root@mysql01~]#cd/mnt/[root@mysql01mnt]#cd/etc/yum.repos.d/[[email protected]]#ls163baklocal.repo[root@mysql......
  • 使用阿里云Rocky Linux镜像源替换默认源
    (1)打开终端,备份默认源(2)更换阿里云镜像源执行以下命令替换默认源sed-e's|^mirrorlist=|#mirrorlist=|g'\-e's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g'\-i.bak\/etc/yum.repos.d/Rocky-*.repo......
  • C语言-内存管理
    简介 C语言的内存管理,分成两部分。一部分是系统管理的,另一部分是用户手动管理的。系统管理的内存,主要是函数内部的变量(局部变量)。这部分变量在函数运行时进入内存,函数运行结束后自动从内存卸载。这些变量存放的区域称为”栈“(stack),”栈“所在的内存是系统自动管理的。用户手动管......
  • Linux知识点 – 随缘更新
    Linux基础篇1.桥接模式:虚拟系统可以和外部系统相互通讯,但是容易造成ip冲突,只能使用与物理机同一个网段2.nat模式:NAT模式与外界通话需要经过物理机(的NAT转换),不会多占一个局域网IP,可以与外部系统相互通讯,不会造成ip冲突,但是外部设备也无法访问虚拟设备3.主机模式:不和外部通讯4......
  • RISCV Ubuntu Linux内核更换
    交叉编译内核#!/bin/bash#LINUXSRC=/root/linuxexportLINUXSRC=/keystone/linuxexportOUTPUT=/keystone/build/linux.build#exportCONFIG=/keystone/conf/linux64-defconfigexportCONFIG=/keystone/build/config-5.19.0-1012-genericexportCROSS_COMPILE=riscv64-u......
  • 一些实用的linux命令
    一、cd的几个小技巧cd–#回到上次所在目录,这个技巧我原来还真是不知道,感觉还是比较有用,省略了很多输入。cd#回到主目录cd~#同样也是回到主目录当进入到一个很深的目录后,一不小心从该目录跳出了,该怎么办呢,别急,这时有cd–命令可以快速跳回上一次cd命令执行之前的目录中,通常也......