一、前言
参考博客 https://blog.csdn.net/F_hawk189/article/details/100126602
二、代码实现
FileMap.h
#pragma once
#include <stdint.h>
#include <string>
#ifdef _MSC_VER
#include <windows.h>
typedef HANDLE MMHandle;
#else
typedef void* MMHandle;
#endif
class CFileMapBase
{
public:
CFileMapBase();
virtual ~CFileMapBase();
bool CreateFileMap(const char* filename, uint32_t size);
uint32_t GetMapSize();
uint32_t GetRealFileSize();
void AddFileSize(uint32_t size, bool bAdd = true);
void SetFileSize(uint32_t size);
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 )
{
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>
template<class T, uint32_t size>
class CFileMapTmp : public CFileMapBase
{
public:
CFileMapTmp();
virtual ~CFileMapTmp();
bool LoadData(const char* filename);
void UnloadData();
bool InsertData(T* data, uint32_t num = 1);
bool RepalceData(int32_t pos, T* data);
bool RefData(int32_t pos, T* data);
bool RefData(int32_t beginPos, int32_t endPos, T* data);
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);
}
|