内存映射封装成类及使用demo
1.类头文件
// MemoryMappedFile.h
#pragma once
#include <windows.h>
class MemoryMappedFile
{
public:
MemoryMappedFile(const wchar_t* fileName);
~MemoryMappedFile();
bool Open();
void Close();
bool IsOpen() const;
bool MapFile(DWORD accessRights = FILE_MAP_READ);
void UnmapFile();
void* GetData() const;
DWORD GetFileSize() const;
bool WriteDataAtOffset(const void* data, size_t dataSize, size_t offset);
private:
const wchar_t* m_fileName;
HANDLE m_fileHandle;
HANDLE m_mappingHandle;
void* m_mappedData;
DWORD m_fileSize;
};
2.类实现
// MemoryMappedFile.cpp
#include "MemoryMappedFile.h"
#include <iostream>
#include <fstream>
#include <filesystem>
MemoryMappedFile::MemoryMappedFile(const wchar_t* fileName)
: m_fileName(fileName), m_fileHandle(nullptr), m_mappingHandle(nullptr), m_mappedData(nullptr), m_fileSize(0)
{
if (!std::filesystem::exists(fileName)) //c++17
{
std::ofstream createFile(fileName, std::ios::binary);
if (createFile)
{
// Set the file size to 1024 byte
const std::streamsize fileSize = 1024;
// 移动文件指针到最后
createFile.seekp(fileSize - 1);
// 写入一个字节以扩展文件大小
createFile.write("", 1);
createFile.close();
}
else
{
std::cout << "Failed to create the file." << std::endl;
}
}
}
MemoryMappedFile::~MemoryMappedFile()
{
Close();
}
bool MemoryMappedFile::Open()
{
m_fileHandle = CreateFileW(
m_fileName,
GENERIC_READ | GENERIC_WRITE, // 访问权限
FILE_SHARE_READ | FILE_SHARE_WRITE, // 共享模式
nullptr,
OPEN_EXISTING, // 打开已存在的文件 CREATE_ALWAYS创建新文件,如果存在则覆盖
FILE_ATTRIBUTE_NORMAL,
nullptr
);
return (m_fileHandle != INVALID_HANDLE_VALUE);
}
void MemoryMappedFile::Close()
{
UnmapFile();
if (m_fileHandle != nullptr && m_fileHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(m_fileHandle);
m_fileHandle = nullptr;
}
}
bool MemoryMappedFile::IsOpen() const
{
return (m_fileHandle != nullptr && m_fileHandle != INVALID_HANDLE_VALUE);
}
bool MemoryMappedFile::MapFile(DWORD accessRights)
{
if (!IsOpen())
return false;
m_mappingHandle = CreateFileMappingW(
m_fileHandle,
nullptr,
accessRights,
//PAGE_READWRITE,
0, // 文件映射大小(高位DWORD)
0, // 文件映射大小(低位DWORD) - 以字节为单位
nullptr
);
if (m_mappingHandle == nullptr)
return false;
m_mappedData = MapViewOfFile(
m_mappingHandle,
FILE_MAP_WRITE | FILE_MAP_READ, // 访问权限
0, // 文件偏移量(高位DWORD)
0, // 文件偏移量(低位DWORD) - 以字节为单位
0
);
if (m_mappedData == nullptr)
{
CloseHandle(m_mappingHandle);
m_mappingHandle = nullptr;
return false;
}
m_fileSize = GetFileSize();
return true;
}
void MemoryMappedFile::UnmapFile()
{
if (m_mappedData != nullptr)
{
UnmapViewOfFile(m_mappedData);
m_mappedData = nullptr;
}
if (m_mappingHandle != nullptr)
{
CloseHandle(m_mappingHandle);
m_mappingHandle = nullptr;
}
}
void* MemoryMappedFile::GetData() const
{
return m_mappedData;
}
DWORD MemoryMappedFile::GetFileSize() const
{
// 创建文件输入流对象,并打开文件
std::ifstream file(m_fileName, std::ios::binary | std::ios::ate);
if (!file.is_open()) {
std::cout << "无法打开文件" << std::endl;
return 1;
}
// 获取文件大小
std::streampos fileSize = file.tellg();
// 关闭文件
file.close();
return static_cast<DWORD>(fileSize);
}
bool MemoryMappedFile::WriteDataAtOffset(const void* data, size_t dataSize, size_t offset)
{
if (!IsOpen() || offset + dataSize > m_fileSize)
return false;
std::memcpy(reinterpret_cast<char*>(m_mappedData) + offset, data, dataSize);
return true;
}
3.用例demo
// main.cpp
#include <iostream>
#include <chrono>
#include "MemoryMappedFile.h"
#include <fstream>
int main()
{
const wchar_t* fileName = L"./memoryMappedTestFile.bin";
// 创建一个内存映射文件对象
MemoryMappedFile mmFile(fileName);
// 记录开始时间点
auto startTime = std::chrono::steady_clock::now();
// 打开文件
if (!mmFile.Open())
{
std::cout << "无法打开文件" << std::endl;
return 1;
}
// 记录结束时间点
auto endTime = std::chrono::steady_clock::now();
// 计算打开时间
auto openTime = std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count();
std::cout << "打开时间:" << openTime << " 微秒" << std::endl;
// 映射文件到内存
if (!mmFile.MapFile())
{
std::cout << "无法映射文件到内存" << std::endl;
mmFile.Close();
return 1;
}
// 获取映射的数据指针和文件大小
LPVOID data = mmFile.GetData();
ULONGLONG fileSize = mmFile.GetFileSize();
// 写:---->写数据
float f_data = 520.0;
size_t dataSize = sizeof(f_data);
size_t offset = 0; // Offset to write the data
if (mmFile.WriteDataAtOffset(&f_data, dataSize, offset))
{
// Data was successfully written
std::cout << "Data written at offset " << offset << std::endl;
}
else
{
// Failed to write data
std::cout << "Failed to write data at offset " << offset << std::endl;
}
// 读:---->读数据
if (data != nullptr)
{
// 将数据视为字节缓冲区,并读取前 fileSize 个字节
unsigned char* buffer = static_cast<unsigned char*>(data);
float result;
std::memcpy(&result, buffer, sizeof(float));
std::cout << result << std::endl;
}
// 解除内存映射并关闭文件
mmFile.UnmapFile();
mmFile.Close();
return 0;
}
4.运行结果
生成文件:
运行结果:
二进制文件查看: