windows平台 文件映射(内存映射)读写操作,已封装成类,可直接使用

内存映射封装成类及使用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.运行结果

生成文件:

运行结果:

二进制文件查看:

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

世尘陌路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值