今日阅读Linux程序设计第四版,找到一个使用mmap函数的实例

问题描述









该程序主要定义一个结构体,随后利用mmap,msync以及munmap函数对其进行内容追加,定位以及修改内容的操作。

先自己实现该代码,随后进行编译

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <sys/mman.h>
  5. #include <fcntl.h>
  6. #include <stdlib.h>
  7. typedef struct{
  8. int integer;
  9. char string[24];
  10. } RECORD;
  11. #define NRECORDS (100)
  12. int main()
  13. {
  14. RECORD record, *mapped;
  15. int i, f;
  16. FILE *fp;
  17. fp = fopen("records.dat","w+");
  18. for(i = 0 ; i < NRECORDS; i++)
  19. {
  20. record.integer = i;
  21. sprintf(record.string,"RECORD-%d",i);
  22. fwrite(&record,sizeof(record),1,fp);
  23. }
  24. fclose(fp);
  25. fp = fopen("records.dat","r+");
  26. fseek(fp,43*sizeof(record),SEEK_SET);
  27. fread(&record,sizeof(record),1,fp);
  28. record.integer = 143;
  29. sprintf(record.string,"RECORD-%d",record.integer);
  30. fseek(fp,43*sizeof(record),SEEK_SET);
  31. fwrite(&record,sizeof(record),1,fp);
  32. fclose(fp);
  33. f = open("records.dat",O_RDWR);
  34. mapped = (RECORD *)mmap(0,NRECORDS*sizeof(record),PROT_READ|PROT_WRITE,MAP_SHARED,f,0);
  35. mapped[43].integer = 243;
  36. sprintf(mapped[43].string,"RECORD-%d",mapped[43].integer);
  37. msync((void *)mapped, NRECORDS*sizeof(record),MS_ASYNC);
  38. munmap((void *)mapped,NRECORDS*sizeof(record));
  39. close(f);
  40. exit(0);
  41. }

随后逐行进行解读

  1. RECORD record, *mapped;
  2. int i, f;
  3. FILE *fp;
  4. fp = fopen("records.dat","w+");
  5. for(i = 0 ; i < NRECORDS; i++)
  6. {
  7. record.integer = i;
  8. sprintf(record.string,"RECORD-%d",i);
  9. fwrite(&record,sizeof(record),1,fp);
  10. }

先fopen创建一个records.dat文件,随后for循环100次,每次record结构体内integer整形值+1,将RECORD结构体record内的integer整形值设定为i

使用sprintf函数,发送格式化输出到record的string字符串中,然后使用fread函数,

fwrite 用于写记录,这里的记录是指一串固定长度的字节,比如一个 int、一个结构体或者一个定长数组。

  1. fwrite(&record,sizeof(record),1,fp);

意思为,从fp流中取得1*sizeof(record)个大小的字节,存放到record结构体当中

  1. fp = fopen("records.dat","r+");
  2. fseek(fp,43*sizeof(record),SEEK_SET);
  3. fread(&record,sizeof(record),1,fp);
  4. record.integer = 143;
  5. sprintf(record.string,"RECORD-%d",record.integer);
  6. fseek(fp,43*sizeof(record),SEEK_SET);
  7. fwrite(&record,sizeof(record),1,fp);
  8. fclose(fp);

随后以读的方式打开record.dat文件,

fseek函数专用于重定向流的位置

参数声明

  1. int fseek(FILE *stream, long int offset, int whence)
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
  • offset -- 这是相对 whence

    的偏移量,以字节为单位。
  • whence -- 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一,其中shence的参数可设置为:

    SEEK_SET 文件的开头

    SEEK_CUR 文件指针的当前位置

    SEEK_END 文件的末尾
  1. fseek(fp,43*sizeof(record),SEEK_SET);

意思为从打开的fp流开头往后第43个record的位置开始操作

  1. fread(&record,sizeof(record),1,fp);
  2. record.integer = 143;
  3. sprintf(record.string,"RECORD-%d",record.integer);

最后将从43号位置开始的record整个读出,放到record变量中,注意,使用指针,此时是从地址读取,因此内存中实际的RECORD【43】也发生了更改,然后将这个位置的string字符数组改为:RECORD-143

  1. fseek(fp,43*sizeof(record),SEEK_SET);
  2. fwrite(&record,sizeof(record),1,fp);
  3. fclose(fp);

将该位置的record重新写回对应内存,关闭这个流

  1. f = open("records.dat",O_RDWR);
  2. mapped = (RECORD *)mmap(0,NRECORDS*sizeof(record),PROT_READ|PROT_WRITE,MAP_SHARED,f,0);
  3. mapped[43].integer = 243;
  4. sprintf(mapped[43].string,"RECORD-%d",mapped[43].integer);
  5. msync((void *)mapped, NRECORDS*sizeof(record),MS_ASYNC);
  6. munmap((void *)mapped,NRECORDS*sizeof(record));

继续打开records.dat文件,采用可读写方式打开

mmap函数用于建立内存映射,并返回映射首地址指针mapped

该步骤将定位到整个RECORD数组的首地址

并修改其中的43号位置的integer

mmap函数详细解释

  1. void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
  • 参数start:指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址
  • 参数length:代表将文件中多大的部分映射到内存。
  • 参数prot:映射区域的保护方式。可以为以下几种方式的组合:

    PROT_EXEC 映射区域可被执行

    PROT_READ 映射区域可被读取

    PROT_WRITE 映射区域可被写入

    PROT_NONE 映射区域不能存取
  • 参数flags:影响映射区域的各种特性
  • 参数fd:要映射到内存中的文件描述符。
  • 参数offset:文件映射的偏移量,通常设置为0
  1. msync((void *)mapped, NRECORDS*sizeof(record),MS_ASYNC);
  2. munmap((void *)mapped,NRECORDS*sizeof(record));

msync函数用于把从传入起始位置开始的修改写回到内存中

munmap函数可用于释放该内存段,将mapped指针指向的部分释放

Linux程序设计第四版一书中对这一部分解释如下:



其实此方法与上一步骤当中的内存映射方法达到目的相同

第一种方法通过定位到流的具体位置做出精确修改,第二种方法通过mmap函数将整个RECORD结构体数组的指针找到,通过该指针找到具体位置。因为在C中,数组本身就是一个指针。

Linux系统下追加记录到文件中的实例代码解读的更多相关文章

  1. linux系统下如何在vscode中调试C++代码

    本篇博客以一个简单的hello world程序,介绍在vscode中调试C++代码的配置过程. 1. 安装编译器 vscode是一个轻量的代码编辑器,并不具备代码编译功能,代码编译需要交给编译器完成. ...

  2. Linux系统下,在文件中查找某个字符串

    在normal模式下按下/即可进入查找模式,输入要查找的字符串并按下回车. Vim会跳转到第一个匹配.按下n查找下一个,按下N查找上一个. Vim查找支持正则表达式,例如/vim$匹配行尾的" ...

  3. Linux系统下查看某文件修改的时间戳

    Linux系统下查看某文件修改的时间戳查看文件时间戳命令:stat awk.txt File: `awk.txt' Size: 20              Blocks: 8          I ...

  4. Linux系统下运行.sh文件

    在Linux系统下运行.sh文件有两种方法,比如我在root目录下有个vip666.sh文件 #chmod +x *.sh的文件名 #./*.sh的文件名 第一种(这种办法需要用chmod使得文件具备 ...

  5. Linux系统下/tmp目录文件重启后自动删除,不重启自动删除10天前的/TMP的文件(转)

    /tmp目录文件重启后自动删除现在知道有ubuntu和solaris系统source:http://blog.chinaunix.net/uid-26212859-id-3567875.html经常会 ...

  6. [转]Windows与Linux系统下的库文件介绍

    什么是库   库文件是一些预先编译好的函数的集合,那些函数都是按照可再使用的原则编写的.它们通常由一组互相关联的用来完成某项常见工作的函数构成,从本质上来说库是一种可执行代码的二进制形式,可以被操作系 ...

  7. Linux系统下进入目录文件需要什么权限?

    在Linux下进入目录需要什么权限? 1--让我们先来了解一下Linux下一个文件有哪些权限?(在linux下一切皆文件) 一个文件可以具有的权限有:可读.可写.可执行权限 r 可读权限---read ...

  8. 修改Linux系统下的最大文件描述符限制

    通常我们通过终端连接到linux系统后执行ulimit -n 命令可以看到本次登录的session其文件描述符的限制,如下: $ulimit -n1024 当然可以通过ulimit -SHn 1024 ...

  9. 并发时-修改Linux系统下的最大文件描述符限制

    通常我们通过终端连接到linux系统后执行ulimit -n 命令可以看到本次登录的session其文件描述符的限制,如下: $ulimit -n1024 当然可以通过ulimit -SHn 1024 ...

  10. Linux培训教程 linux系统下分割大文件的方法

    在linux中分割大文件,比如一个5gb日志文件,需要把它分成多个小文件,分割后以利于普通的文本编辑器读取. 有时,需要传输20gb的大文件,Linux培训 教程件到另一台服务器,也需要把它分割成多个 ...

随机推荐

  1. OI是什么?

    从OI谈起 提到OI,也许很多人并不清楚这是怎么一回事.对于在学校就学习过数学.物理.化学和生物的同学们来说,"国际五项学科奥林匹克竞赛"中的这四门是相当熟悉了(相对OI来说).而 ...

  2. [深度学习]Keras利用VGG进行迁移学习模板

    # -*- coding: UTF-8 -*- import keras from keras import Model from keras.applications import VGG16 fr ...

  3. 使用Spring MVC框架进行前台页面跳转时,跳转到的新页面中文显示乱码的问题解决

    使用Spring MVC框架进行前台页面跳转时,跳转到的新页面中文显示乱码的问题解决   摘要:我昨天花了一天时间学习了SSM项目搭建,却在最终的编码问题上拉胯了,在使用Spring MVC框架进行前 ...

  4. 安装pytorch-gpu的经验与教训

    首先说明 本文并不是安装教程,网上有很多,这里只是自己遇到的一些问题 我是以前安装的tensorflow-gpu的,但是发现现在的学术论文大部分都是用pytorch复现的,因此才去安装的pytorch ...

  5. YMOI 2019.6.22

    题解 YMOI 2019.6.22 lia麦頔溜了,缺了lia麦頔的排名仅供参考 不过分数还是暴露无遗 T1 邪恶入侵 简易题干: 在三维空间内有一些点,点之间有双向边.每一次询问给出一个m,只有边权 ...

  6. Linux c 程序自动启动自己

    在程序自动升级的时候需要自己重新启动自己 #include <stdio.h> #include <stdlib.h> #include <unistd.h> in ...

  7. 安装postcss-px-to-viewport 配置postcss.config.js 报错Error: true is not a PostCSS plugin

    因项目需要,用户突然要坚持小屏幕也要观看大屏代码,临时解决方案是加了一个postcss-px-to-viewport ,安装过程中报错Error: true is not a PostCSS plug ...

  8. IOS(XCode)嵌入Unity模块

    今天下午明明要弄明白Android Studio出AAR给Unity用的,结果发现好多问题,小黑心里苦啊,整不明白了呀,让我做Unity吧... 好了,废话不给大家多说了,今天小黑给大家带来,如何在I ...

  9. get请求与post请求的区别

    大小限制 get请求一般通过url传输的数据量时比较少的,最多传3~5个参数,如果要传递多个参数,要在url地址中利用"&"符号拼接多个参数, 栗子:/test/demo. ...

  10. Redis-05持久化

    1 Redis持久化 RDB(Redis DataBase) AOF(Append Only File) 2 RBD 2.1 基本说明 在指定的时间间隔内将内存中的数据集快照写入磁盘文件,它恢复时将快 ...