IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> C++内存映射文件 -> 正文阅读

[游戏开发]C++内存映射文件

一、前言

参考博客 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);
}
  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-04-26 12:08:57  更:2022-04-26 12:11:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/17 0:16:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码