c++/MFC 封裝好的文件內存映射類

整理日: 2015年2月16日app

首先介紹內存映射文件操做------函數的用法以及前後執行順序函數

// 第一步:建立文件
HANDLE hFile = CreateFileForMapping(_T("MyMemFile.dat"), GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(hFile != 0);

// 第二步:建立內存映射文件對象
HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 1024,
_T("MyMapppingFile"));
ASSERT(hMapFile != 0);

// 第三步:獲取內存映射文件對象視圖
BYTE* pData = (BYTE*)MapViewOfFile(hMapFile, FILE_MAP_WRITE, 0, 0, 1024);
ASSERT(pData != NULL);
// 對 pData 指針進行讀寫操做
// ......

// 第四步:取消內存視圖映射
UnmapViewOfFile(pData);

// 第五步:關閉內存映射對象句柄
CloseHandle(hMapFile);

// 第六步:關閉文件句柄
CloseHandle(hFile);

header file指針

// MapFile.h : header file
#if !defined(AFX_MAPFILE_H__D067E5C8_C4D7_4569_A6BB_9D651FB3F396__INCLUDED_)
#define AFX_MAPFILE_H__D067E5C8_C4D7_4569_A6BB_9D651FB3F396__INCLUDED_
#if _MSC_VER < 1000
#pragma once
#endif // _MSC_VER < 1000

/////////////////////////////////////////////////////////////////////////////
// CMapFile class 使用說明:
// 1 一個對象,打開文件映射以後,當即處理,處理完以後才能再用它打開另外一個文件映射
class CMapFile
{

public:
    CMapFile(); // protected constructor used by dynamic creation
    virtual ~CMapFile();

    // Attributes
    PVOID m_pvFile;
    BOOL m_bSmooth; // 爲TRUE表示不阻塞,即不彈出任何對話框

private:
    HANDLE hFileMap;

    // Operations
public:
    BOOL OpenMapFile(CString sFile);

    // Implementation
    BOOL CloseMapFile();
};
// {{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MAPFILE_H__D067E5C8_C4D7_4569_A6BB_9D651FB3F396__INCLUDED_)

cpp filecode

// MapFile.cpp : implementation file
#include "stdafx.h"
#include "MapFile.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// CMapFile
CMapFile::CMapFile()
{
    m_pvFile = NULL;
    m_bSmooth = FALSE;
}

CMapFile::~CMapFile()
{
    if (NULL != m_pvFile)
    {
        UnmapViewOfFile(m_pvFile);
        m_pvFile = NULL;
    }
}

// CMapFile operation handlers
// 空文件會彈出 map could not be opened,在裏面敲一個回車,就行了
BOOL CMapFile::OpenMapFile(CString sFile)
{
    if (NULL != m_pvFile)
    {
        UnmapViewOfFile(m_pvFile); // 在當前應用程序的內存地址空間解除對一個文件映射對象的映射
        m_pvFile = NULL;
    }

    // 1:建立或打開一個文件內核對象: Open the file for reading and writing.
    // 這裏CreateFile函數的參數,路徑不管是否有空格都不能有引號,有引號的時候會出錯。
    HANDLE hFile = CreateFile(sFile, GENERIC_READ | GENERIC_WRITE, 0, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    // 因爲hFile即便爲INVALID_HANDLE_VALUE,下面的CreateFileMapping仍然能夠正常運行,
    // 因此這裏必定要對hFile進行檢查!
    if (hFile == INVALID_HANDLE_VALUE)
    {
        if (!m_bSmooth) // 爲TRUE表示不阻塞,即不彈出任何對話框
        {
            AfxMessageBox(_T("File[") + sFile +
                _T("]could not be opened. Maybe it's not exist."));
        }
        return FALSE;
    }

    // 2:建立一個文件映射內核對象
    DWORD dwFileSize = GetFileSize(hFile, NULL);
    // 獲取文件大小=文件長度+(WCHAR)'\0'(ssume the whole file can be mapped)
    // Create the file-mapping object. The file-mapping object is 1 character
    // bigger than the file size so that a zero character can be placed at the
    // end of the file to terminate the string (file). Because I don't yet know
    // if the file contains ANSI or Unicode characters, I assume worst case
    // and add the size of a WCHAR instead of CHAR.
    hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, dwFileSize + 1,
        /* sizeof(WCHAR)==2,sizeof(char)==1 */
        // 由於咱們要在文件的末尾加上一個字符串的結束符'\0', 當咱們將這個文件映射到內存中時,
        // 咱們就能夠像操做字符串同樣地來操做文件了。
        // 若是該文件小於設定的大小,本函數將擴展該文件的大小,使磁盤上的文件變大。
        // 這樣當之後將該文件做爲內存映射 文件使用時,物理存儲器就已經存在了。
        NULL // 這個文件映射對象的名字用於與其餘進程共享該對象,這裏咱們還用不到。
        );
    if (hFileMap == NULL)
    {
        if (!m_bSmooth)
        {
            AfxMessageBox(_T("File[") + sFile +
                _T("] map could not be opened. May be it's empty."));
        }
        return FALSE;
    }

    // 3:將文件數據映射到進程的地址空間:
    // 當建立了一個文件映射對象以後,仍然必須讓系統爲文件的數據保留一個地址空間區域,
    // 並將文件的數據做爲映射到該區域的物理存儲器進行提交。
    m_pvFile = MapViewOfFile(hFileMap, /* FILE_MAP_WRITE */ FILE_MAP_READ,
        0, 0, 0); // 獲取映射文件在內存中的首地址
    // CloseHandle(hFileMap);// 關閉內存映射對象句柄
    if (m_pvFile == NULL)
    {
        if (!m_bSmooth)
        {
            AfxMessageBox(_T("Could not map view of file[") + sFile + _T("]."));
        }
        return FALSE;
    }
    // 4:既然咱們經過pvFile獲得了映象視圖的起始地址,那麼能夠對視圖作一些操做了:
    // ANSI版本:
    // PSTR pchANSI = (PSTR) m_pvFile;
    // UNICODE版本:
    // PWSTR pchUnicode = (PWSTR) pvFile;如char* sz=(char*)m_pvFile;sz[dwFileSize/sizeof(char)]='\0';
    // 5:從進程的地址空間中撤銷文件數據的映象:
    // UnmapViewOfFile(m_pvFile); // 封裝爲類,映象要在其餘地方使用因此這句話要去掉
    // 6:關閉文件映射對象和文件對象:
    // CloseHandle(hFileMap);
    // 咱們改變了文件的長度,所以要從新設置文件的結束符以刪除留在文件尾部的多餘內容(好比刪除咱們先前加到文件末尾的'\0'字符)
    SetFilePointer(hFile, dwFileSize, NULL, FILE_BEGIN);
    SetEndOfFile(hFile); // 設定當前文件指針所在處爲文件結束處.該處後面的內容將被刪除
    CloseHandle(hFile);
    return TRUE;
}

BOOL CMapFile::CloseMapFile()
{
    if (NULL != m_pvFile)
    {
        // 取消內存視圖映射
        if (UnmapViewOfFile(m_pvFile))
        {
            m_pvFile = NULL;
            CloseHandle(hFileMap); // 關閉內存映射對象句柄
            return TRUE;
        }
        return FALSE;
    }
    return TRUE;
}
相關文章
相關標籤/搜索