前言

最近一段项目上总是出现一些因为文件没有及时保存而产生的问题,因此小编就在网上寻找到了这个文件存储方法mmap,这里为大家进行下简单的介绍。

简介

首先我们需要对iOS中各App的运行环境进行了解,进程即App运行的基本单位,进程之间相对独立。iOS系统中App运行的内存空间地址是虚拟空间地址,存储数据是在各自的沙盒。当我们在App中去读写沙盒中的文件时,我们会使用NSFileManager去查找文件,然后可以使用NSData去加载二进制数据。文件操作的更底层实现过程,是使用linux的read()、write()函数直接操作文件句柄(也叫文件描述符、fd)。

在操作系统层面,当App读取一个文件时,实际是有两步:先将文件从磁盘读取到物理内存,再从系统空间拷贝到用户空间(可以认为是复制到系统给App统一分配的内存)。

iOS系统使用页缓存机制,通过MMU(Memory Management Unit)将虚拟内存地址和物理地址进行映射,并且由于进程的地址空间和系统的地址空间不一样,所以还需要多一次拷贝。

而mmap将磁盘上文件的地址信息与进程用的虚拟逻辑地址进行映射,建立映射的过程与普通的内存读取不同:正常的是将文件拷贝到内存,mmap只是建立映射而不会将文件加载到内存中。App 只管往里面写数据,由 iOS 负责将内存回写到文件,不必担心 crash 导致数据丢失。

下面两个图分别显示进程读取磁盘文件的过程和使用mmap进行文件映射的过程。

图1

图2

实现代码

以官网的demo为例,其他的代码很简明直接,核心就在于mmap函数。

void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);

*outDataPtr = mmap(NULL,                   size,                   PROT_READ|PROT_WRITE,                   MAP_FILE|MAP_SHARED,                   fileDescriptor,                   0);

start:映射开始地址,设置NULL则让系统决定映射开始地址;length:映射区域的长度,单位是Byte;prot:映射内存的保护标志,主要是读写相关,是位运算标志;(记得与下面fd对应句柄打开的设置一致)flags:映射类型,通常是文件和共享类型;fd:文件句柄;off_toffset:被映射对象的起点偏移;

读写的例子如下:

#import "ViewController.h"#import #import 

int MapFile(const char * inPathName, void ** outDataPtr, size_t * outDataLength, size_t appendSize){    int outError;    int fileDescriptor;    struct stat statInfo;

    // Return safe values on error.    outError = 0;    *outDataPtr = NULL;    *outDataLength = 0;

    // Open the file.    fileDescriptor = open( inPathName, O_RDWR, 0 );    if( fileDescriptor 0 )    {        outError = errno;    }    else    {        // We now know the file exists. Retrieve the file size.        if( fstat( fileDescriptor, &statInfo ) != 0 )        {            outError = errno;        }        else        {            ftruncate(fileDescriptor, statInfo.st_size + appendSize);            fsync(fileDescriptor);            *outDataPtr = mmap(NULL,                               statInfo.st_size + appendSize,                               PROT_READ|PROT_WRITE,                               MAP_FILE|MAP_SHARED,                               fileDescriptor,                               0);            if( *outDataPtr == MAP_FAILED )            {                outError = errno;            }            else            {                // On success, return the size of the mapped file.                *outDataLength = statInfo.st_size;            }        }

        // Now close the file. The kernel doesn’t use our file descriptor.        close( fileDescriptor );    }

    return outError;}

void ProcessFile(const char * inPathName){    size_t dataLength;    void * dataPtr;    char *appendStr = " append_key";    int appendSize = (int)strlen(appendStr);    if( MapFile(inPathName, &dataPtr, &dataLength, appendSize) == 0) {        dataPtr = dataPtr + dataLength;        memcpy(dataPtr, appendStr, appendSize);        // Unmap files        munmap(dataPtr, appendSize + dataLength);    }}

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view.    NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"test.data"];    NSLog(@"path: %@", path);    NSString *str = @"test str";    [str writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];

    ProcessFile(path.UTF8String);    NSString *result = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];    NSLog(@"result:%@", result);}

最后

mmap就是文件的内存映射,通常读取文件是将文件读取到内存,会占用真正的物理内存;而mmap是用进程的内存虚拟地址空间去映射实际的文件中,这个过程由操作系统处理。mmap不会为文件分配物理内存,而是相当于将内存地址指向文件的磁盘地址,后续对这些内存进行的读写操作,会由操作系统同步到磁盘上的文件。这种操作也节省了很多内存占用,极大的提升了进程的性能。






搜狗测试微信号:Qa_xiaoming

搜狗测试QQ粉丝群:459645679

mmap映射大于4g的文件_iOS文件内存映射——MMAP相关推荐

  1. 内外网映射 html缓存问题_浅谈内存映射

    写在前面:这是本人初入研究方法时做的笔记作为学习的输出,其中可能存在一些认知上的错误.若您有自己的见解,希望你可以在本文结尾给我留言或直接邮件联系我,与我讨论. 谢谢! email:zhaos@nbj ...

  2. mmap映射大于4g的文件_浅谈mmap_刘伟

    奇技指南 作者说:最近在工作中遇到一个mmap使用相关的问题,造成了一定的困惑,于是花了些时间补了下 mmap的功课,在这里分享给大家,错误和不足之处大家多指教. 相关背景知识 说到mmap的使用,我 ...

  3. linux 文件IO与内存映射:内存映射

    前言 前面几篇我们学习了用户空间的IO缓冲区,以及IO缓冲区的分散聚合IO技术. 为了减少系统调用的次数,提升系统性能,操作系统开发者门提出了这么多的缓存技术. 但是到这里这些技术同样有不足的地方:不 ...

  4. matlab读int16读文件_MATLAB: 使用内存映射加快文件读写

    内存映射是将磁盘上某文件的一部分或整个文件映射到应用程序地址空间内某个地址范围的一种机制.然后,应用程序可采用与访问动态内存相同的方法访问磁盘上的文件.与使用fread和fwrite等函数相比,能够加 ...

  5. C语言读取大文件的问题 内存映射

    2019独角兽企业重金招聘Python工程师标准>>> [Ref] Windows对文件的读写提供了很丰富的操作手段,如: 1. FILE *fp, fstearm...; (C/C ...

  6. java内存映射缓存,java – 用于数据库实现的内存映射的MappedByteBuffer或直接ByteBuffer?...

    这看起来像一个长期的问题,因为所有的上下文.下面的小说里有两个问题.感谢您抽出时间阅读并提供帮助. 情况 我正在开展可扩展的数据存储实现,可以支持在32位或64位系统上处理数据文件,从几KB到TB或更 ...

  7. mmap映射大于4g的文件_尴尬,win10镜像文件install.wim大于4G,如何将它装进U盘

    大多数现代操作系统都将UEFI作为默认固件,这是一件好事,但是,要想在UEFI系统上安装Windows 10,需要使用FAT32文件系统创建可引导的驱动器,而FAT32文件系统只能存储小于4GB的文件 ...

  8. linux文件IO与内存映射:用户空间的IO缓冲区

    文章目录 用户空间IO缓冲区产生 IO缓冲区 描述 IO缓冲区的写模式 自定义IO缓冲区 用户空间IO缓冲区产生 系统调用过程中会产生的开销如下: 切换CPU到内核态 进行数据内容的拷贝,从用户态到内 ...

  9. linux文件IO与内存映射:分散/聚集IO技术(scatter-gather)

    前言 根据上文我们学习到的用户空间的IO缓冲区,操作系统为了减少系统调用的次数,节省系统开销,提出了用户空间的IO缓冲区,即为用户空间的文件读写开辟一段可以利用setvbuf配置大小的内存空间来作为文 ...

最新文章

  1. 微服务平台改造落地解决方案设计
  2. pythonos pathjson_Python Json数据文件操作原理解析
  3. docker 不包含依赖 打包_Docker容器技术(概念篇)
  4. Eclipse中输入系统变量和运行参数
  5. 【学习笔记】MOOC 数学文化赏析 笔记
  6. 盒子模型(W3C盒子和IE盒子)
  7. 小程序-蓝牙打印写数据部分CPCL指令方式,解决偶尔打印打印机指令情况(传输的数据被风吹跑了~)
  8. 男人怎么读 萨瓦迪卡!还是萨瓦迪卡不!
  9. evplayer2可以多设备登录吗_EVPlayer2
  10. VR全景拍摄如何拍摄?如何使用拍摄器材?
  11. python--破解滑动验证码
  12. 跳槽谋发展:人生发展的一些思考和最近找工作的坎坷经历
  13. 中国最贵海报设计师!黄海究竟凭什么?
  14. Android懒人库
  15. PC移植安卓---2018/04/26
  16. 图像处理45-grabCut图像分割
  17. 基于51单片机的数字电压表(ADC0832)(Proteus仿真+程序)
  18. SpringMvc中关于@ResponseBody和HashMap的用法
  19. win10 office activation tools
  20. 一篇文章读懂 React and redux 前端开发 -DvaJS, a lightweight and elm-style framework.

热门文章

  1. GNS3错误7200:无法开始Dynamips于端口7200
  2. 认证登录时代来临,主流验证登录方式盘点
  3. codevs——1958 刺激
  4. C++ explicit constructor/copy constructor note
  5. JAX-RS(Java API for RESTful Web Services)常用注解
  6. window COM调试2[转]
  7. android 渠道包 占位符配置,Android打包
  8. 深度强化学习_深度学习理论与应用第8课 | 深度强化学习
  9. c 普通的文本变成注释文本的快捷键_收藏了!IntelliJ IDEA 2019 快捷键开发手册
  10. startsWith(),endsWith()的作用,用法,判断字符串a 是不是以字符串b开头或结尾