使用内存映射实现本地缓存

本来程序中一些数据需要在下次重启后能够恢复继续使用,一般比较好的办法是直接嵌入sqlite数据库或者嵌入leveldb,但是需要引入第三方库,略麻烦,因此打算自己实现。

实现思路

自己实现最简单就是使用WinAPI操作INI文件,一个读API一个写API,非常简单方便,但是曾经出现过一个项被写两次的问题,心有余悸,另外也可以预见这种频繁的API操作肯定对磁盘性能有影响。

另外一种自定义格式写文件,将文件读取出来,需要写入的时候更新内存并刷新到磁盘文件,同样相对可靠性能没那么好。

不过,基于上面的思想,其实我们可以使用内存映射的方式来实现。

实现方法

内存映射思想就是将文件映射成一片内存,然后操作内存就相当于操作文件,这样其实操作也方便,性能也好,但是因为是内存操作,需要自己去做内存分布排列,这是需要注意的地方。实现过程大概如下

  1. 使用CreateFile打开文件
  2. 创建内存映射,空文件映射会失败
  3. 获取映射内存,映射大小必须不能大于文件大小

由于第一次使用,会创建缓存文件,且缓存文件大小为0,因此当文件为空时,需要往里面写一次数据,以保证创建内存映射成功。

HANDLE file = CreateFile("cache.m", GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if(filehandle_ == INVALID_HANDLE_VALUE){
printf("创建缓存文件失败 %d", GetLastError());
return false;
}

DWORD len = GetFileSize(file, NULL);
if(len == 0) {
struct CacheStruct cache;
memset(&cache, 0, sizeof(cache));
WriteFile(file, &cache, sizeof(cache), NULL, NULL);
}

HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READWRITE, 0,0, NULL);
if(filemapping_ == NULL){
printf("创建映射文件失败 %d", GetLastError());
return false;
}

UCHAR * mem = (UCHAR *)MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, len);
if(!mem){
printf("MapViewOfFile失败 %d", GetLastError());
return false;
}

return true;

这样就映射成功了,直接操作 mem 地址的内存就相当于操作文件,注意内存已经固定为 len 长度了,写入需要注意。上面例子是通过 struct CacheStruct 管理内存分布的,简单的定义为固定数组形式的结构。

struct CacheStruct {
char data1[MAX_PATH];
char data2[MAX_PATH];
};

其他想法

总体上相当于是有一块内存可使用了,那么可以通过 palcement new 实现一些功能。另外就是自实现类似 vector 之类的容器。

最近的文章

FFMPEG推流摄像头

一般的直播网站都使用OBS推流,其实ffmpeg也可以推流,在无界面环境下就可以推流使用。本文以Windows下为例,简单介绍下使用ffmpeg工具推流的方法和步骤。 下载安装下载地址:https://ffmpeg.zeranoe.com/builds/ 选择版本(默认即可),选择自己系统架构,L …

技术 继续阅读
更早的文章

简单解析海康PS流获取H264

在用海康SDK获取H264视频流的时候,其实从海康的SDK里面基本是没有的,海康的SDK介绍使用是通过自身的PlayM4解码成图片的,并非我们想要的H264。项目里面使用的是海康提供的AnalyzeData库,但是我并没有从海康官网找到下载,应该是PS格式解析库。 分析其实通过Wireshark本地 …

技术 继续阅读