0
点赞
收藏
分享

微信扫一扫

C++内存映射文件

624c95384278 2022-04-24 阅读 52

一、前言

参考博客 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);
}
举报

相关推荐

0 条评论