一、前言
参考博客 https://blog.csdn.net/F_hawk189/article/details/100126602
二、代码实现
FileMap.h
#pragma once
#include <stdint.h>
#include <string>
/**
* @brief 内存映射文件类
*/
#ifdef _MSC_VER
#include <windows.h>
typedef HANDLE MMHandle;
#else
typedef void* MMHandle;
#endif
class CFileMapBase
{
public:
CFileMapBase();
virtual ~CFileMapBase();
/**
* @brief 创建内存映射文件
* @param filename 文件路径
* @param size 映射大小
* @return 创建是否成功
*/
bool CreateFileMap(const char* filename, uint32_t size);
/**
* @brief 得到内存映射文件大小
* @return 映射文件大小
*/
uint32_t GetMapSize();
/**
* @brief 得到实际使用的文件大小
* @return 实际使用的文件大小
*/
uint32_t GetRealFileSize();
/**
* @brief 实际使用的大小改变
* @param size 改变的大小
* @param bAdd true=增加 false=减小
*/
void AddFileSize(uint32_t size, bool bAdd = true);
/**
* @brief 直接设置实际使用的大小
* @param size 设置大小值
*/
void SetFileSize(uint32_t size);
/**
* @brief 关闭内存映射,存入磁盘
* @return
*/
bool DestroyMapView();
protected:
std::string m_fileName; ///>映射文件
uint32_t m_mmapSize; ///>映射大小
uint32_t m_useSize; ///>实际使用大小
char* m_pMmap; ///>映射指针位置
MMHandle m_handle; ///>映射文件句柄
};
FileMap.cpp
#include "FileMap.h"
#include <algorithm>
#ifdef _MSC_VER
#include <windows.h>
#else
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif
CFileMapBase::CFileMapBase() : m_handle(nullptr), m_pMmap(nullptr), m_useSize(0), m_mmapSize(0){
}
CFileMapBase::~CFileMapBase(){
}
bool CFileMapBase::CreateFileMap(const char* filename, uint32_t size)
{
m_fileName = filename;
#ifdef _MSC_VER
HANDLE hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return false;
}
uint32_t fileLen = ::GetFileSize(hFile, NULL);
#else
int32_t fd = open(filename, O_CREAT | O_RDWR, S_IRWXU);
if (fd < 0)
{
CLog::Instance().WriteLog("CFileMapBase", "CreateFileMap", "open failed Errno=%d,file=%s", errno, filename);
return false;
}
struct stat fileStat;
if (fstat(fd, &fileStat) == -1)
{
CLog::Instance().WriteLog("CFileMapBase", "CreateFileMap", "fstat failed Errno=%u,file=%s", errno, filename);
return false;
}
uint32_t fileLen = fileStat.st_size;
#endif
uint32_t mmsize = std::max<uint32_t>(size, fileLen);
if (mmsize <= 0)
{
#ifdef _MSC_VER
CloseHandle(hFile);
#else
close(fd);
#endif
return false;
}
#ifdef _MSC_VER
MMHandle hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, mmsize, NULL);
if (!hMap)
{
CloseHandle(hFile);
return false;
}
CloseHandle(hFile);
void* pData = MapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0);
if (!pData)
{
CloseHandle(hMap);
return false;
}
#else
mmsize = ftruncate(fd, mmsize); //改变文件大小
if (mmsize == -1)
{
return false;
}
MMHandle hMap = mmap(NULL, mmsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, SEEK_SET);
if (hMap == MAP_FAILED)
{
close(fd);
return false;
}
close(fd);
#endif
m_handle = hMap;
#ifdef _MSC_VER
m_pMmap = (char*)pData;
#else
m_pMmap = (char*)hMap;
#endif
m_mmapSize = mmsize;
if (fileLen == 0)
{
*((int32_t*)m_pMmap) = 0;
}
m_useSize = *((int32_t*)m_pMmap);
return true;
}
uint32_t CFileMapBase::GetMapSize()
{
return m_mmapSize;
}
uint32_t CFileMapBase::GetRealFileSize()
{
return m_useSize;
}
void CFileMapBase::AddFileSize(uint32_t size, bool bAdd /* = true */)
{
bAdd ? m_useSize += size : m_useSize -= size;
*(int32_t*)m_pMmap = m_useSize;
}
void CFileMapBase::SetFileSize(uint32_t size)
{
m_useSize = size;
*(int32_t*)m_pMmap = m_useSize;
}
bool CFileMapBase::DestroyMapView()
{
#ifdef _MSC_VER
if (m_pMmap) UnmapViewOfFile(m_pMmap);
if (m_handle) CloseHandle(m_handle);
#else
if (m_handle) munmap(m_handle, m_mmapSize);
#endif
m_pMmap = nullptr;
m_mmapSize = m_useSize = 0;
m_handle = nullptr;
return true;
}
FileMapTmp.h
#pragma once
#include "filemap.h"
#include <shared_mutex>
/**
* @brief 内存映射文件使用模板类
* @tparam T 使用内存映射的文件结构
*/
template<class T, uint32_t size>
class CFileMapTmp : public CFileMapBase
{
public:
CFileMapTmp();
virtual ~CFileMapTmp();
/**
* @brief 载入文件
* @param filename 文件路径
* @return true=载入成功 false=载入失败
*/
bool LoadData(const char* filename);
/**
* @brief 卸载文件
*/
void UnloadData();
/**
* @brief 插入数据
* @param data 插入数据地址指针
* @param num 插入数量
* @return true=成功 false=失败
*/
bool InsertData(T* data, uint32_t num = 1);
/**
* @brief 覆盖数据
* @param data 覆盖数据地址指针
* @return true=成功 false=失败
*/
bool RepalceData(int32_t pos, T* data);
/**
* @brief 读取数据
* @param pos 读取位置
* @param data 输出读取到的数据
* @return true=成功 false=失败
*/
bool RefData(int32_t pos, T* data);
/**
* @brief 读取数据
* @param beginPos 读取起始位置
* @param endPos 读取结束位置
* @param data 输出读取到的数据
* @return ture=成功 false=失败
*/
bool RefData(int32_t beginPos, int32_t endPos, T* data);
/**
* @brief 实际使用的数据总数
* @return 数量
*/
uint32_t GetDataNumber() const;
private:
T* m_pData; ///> 数据起始位置指针
std::shared_mutex m_lock; ///>数据共享锁
};
template<class T, uint32_t size>
CFileMapTmp<T, size>::CFileMapTmp()
{
m_pData = nullptr;
}
template<class T, uint32_t size>
CFileMapTmp<T, size>::~CFileMapTmp()
{
}
template<class T, uint32_t size>
bool CFileMapTmp<T, size>::LoadData(const char* filename)
{
m_fileName = filename;
if (!m_pMmap)
{
if (!CreateFileMap(filename, sizeof(T) * size + sizeof(uint32_t)))
{
return false;
}
}
m_pData = (T*)(m_pMmap + sizeof(int32_t));
return true;
}
template<class T, uint32_t size>
void CFileMapTmp<T, size>::UnloadData()
{
DestroyMapView();
}
template<class T, uint32_t size>
bool CFileMapTmp<T, size>::RefData(int32_t pos, T* data)
{
std::shared_lock<std::shared_mutex> lck(m_lock);
uint32_t realSize = GetRealFileSize() / sizeof(T);
if (realSize <= static_cast<uint32_t>(pos))
{
return false;
}
memcpy(data, m_pData + pos, sizeof(T));
return true;
}
template<class T, uint32_t size>
bool CFileMapTmp<T, size>::RefData(int32_t beginPos, int32_t endPos, T* data)
{
std::shared_lock<std::shared_mutex> lck(m_lock);
uint32_t realSize = GetRealFileSize() / sizeof(T);
if (beginPos > endPos)
{
std::swap(beginPos, endPos);
}
if (realSize <= static_cast<uint32_t>(beginPos))
{
return false;
}
if (realSize <= static_cast <uint32_t>(endPos)) endPos = static_cast <int32_t>(realSize - 1);
memcpy(data, m_pData + beginPos, (endPos - beginPos + 1) * sizeof(T));
return true;
}
template<class T, uint32_t size>
bool CFileMapTmp<T, size>::InsertData(T* data, uint32_t num)
{
std::unique_lock<std::shared_mutex> lck(m_lock);
uint32_t realSize = GetRealFileSize();
uint32_t addSize = num * sizeof(T);
uint32_t chgSize = realSize + sizeof(int32_t) + addSize;
if (chgSize > GetMapSize())
{
DestroyMapView();
uint32_t newSize = realSize + sizeof(int32_t) + size;
while (newSize < chgSize)
{
newSize += size;
}
if (!CreateFileMap(m_fileName.c_str(), newSize))
{
return false;
}
}
realSize = GetRealFileSize() / sizeof(T);
m_pData = (T*)(m_pMmap + sizeof(uint32_t));
memcpy(m_pData + realSize, data, addSize);
AddFileSize(addSize);
return true;
}
template<class T, uint32_t size>
bool CFileMapTmp<T, size>::RepalceData(int32_t pos, T* data)
{
std::unique_lock<std::shared_mutex> lck(m_lock);
memcpy(m_pData + pos, data, sizeof(T));
return true;
}
template<class T, uint32_t size>
uint32_t CFileMapTmp<T, size>::GetDataNumber() const
{
return m_useSize / sizeof(T);
}