浅墨浓香

想要天亮进城,就得天黑赶路。

导航

第17章 内存映射文件(3)_稀疏文件(Sparse File)

Posted on 2015-11-07 17:25  浅墨浓香  阅读(2085)  评论(0编辑  收藏  举报

17.8 稀疏调拨的内存映射文件

17.8.1 稀疏文件简介

(1)稀疏文件(Sparse File):指的是文件中出现大量的0数据,这些数据对我们用处不大,但是却一样的占用空间。NTFS文件系统对此进行了优化,那些无用的0字节被用一定的算法压缩起来。例如声明一个很大的稀疏文件(如100GB),这个文件实际上并不需要占用那么大的空,内部都是一些无用的0数据,那么NTFS就会利用算法释放这些无用的0字节空间,这是对磁盘占用空间的一种优化。但要注意FAT32并不支持稀疏文件的压缩

(2)与稀疏文件操作有关的函数

  ①判断系统是否支持稀疏文件:GetVolumeInformation,通过传出的参数lpFileSystemFlags & FILE_SUPPORTS_SPARSE_FILES判断结果是否为FILE_SUPPORTS_SPARSE_FILES。

  ②判断一个文件是否是稀疏文件:GetFileInformationByHandle

    BY_HANDLE_FILE_INFORMATION stFileInfo;

    GetFileInformationByHandle(hFile, &stFileInfo);

    当stFileInfo.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE为TRUE时表示稀疏文件。

  ③产生一个稀疏文件:DeviceIoControl(hFile,FSCTL_SET_SPARSE,…);

  大部分文件,在改变它的EndOfFile的时候,中间的空白会被操作系统填0,也就是说,如果用SetFilePointer和SetEndOfFile来产生一个很大的文件,那么这个文件它占用的是真正的磁盘空间,即使里面全是0,系统默认的也会在DeviceIoControl()中的ControlCode里用FSCTL_SET_ZERO_DATA标记,这个标记使得那些文件空洞被0所填充。为了节省磁盘空间,我们必须把一个文件声明为稀疏文件,以便让系统把那些无用的0字节压缩,并释放相应的磁盘空间,要将标记改为FSCTL_SET_SPARSE。

  ④查找稀疏文件中包含非零数据的范围

    DeviceIoControl(hFile, FSCTL_QUERY_ALLOCATED_RANGES,…);

17.8.2 以稀疏文件为后备存储器的内存映射文件(一般的使用步骤)

(1)创建文件:hFile = CreateFile(…);

(2)产生稀疏文件:

  DeviceIoControl(hFile, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dw, NULL));

(3)创建内存映射文件对象:

  hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE,…);

(4)映射到进程的地址空间

   pvFile = MapViewOfFile(hFileMap, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0);

(5)读、写文件(像直接读写内存一样的读写文件)

(6)撤消映射:UnmapViewOfFile(pvFile);

(7)关闭句柄:CloseHandle(hFileMap);CloseHandle(hFile);

【MMFSparse程序】创建一个NTFS稀疏文件为后备存储器的内存映射文件

 

//MMFSparse.cpp

/************************************************************************
Module:  MMFSparse.cpp
Notices: Copyright(c) 2008 Jeffrey Ritcher & Christophe Nasarre
************************************************************************/
#include "../../CommonFiles/CmnHdr.h"
#include "SparseStream.h"
#include "resource.h"
#include <tchar.h>
#include <strsafe.h>

//////////////////////////////////////////////////////////////////////////
//定义一个稀疏文件的内存映射文件操作类
class CMMFSparse :public CSparseStream{
private:
    HANDLE m_hFileMap;  //文件映射对象
    PVOID  m_pvFile;    //视图开始的地址

public:
    //构造函数(hStream为外部传进来的文件对象的句柄)
    CMMFSparse(HANDLE hStream = NULL, DWORD dwStreamSizeMaxLow = 0,
               DWORD dwStreamSizeMaxHigh = 0){
        Initialize(hStream, dwStreamSizeMaxLow, dwStreamSizeMaxHigh);
    }
    
    //关闭Sparse MMF
    virtual ~CMMFSparse(){ ForceClose(); }

    //创建一个以稀疏文件为后备存储器的MMF对象,并映射到进程的地址空间
    BOOL Initialize(HANDLE hStream = NULL, DWORD dwStreamSizeMaxLow = 0,
                    DWORD dwStreamSizeMaxHigh = 0);

    //将CMMFSparse类的对象指针,转化为视图的第1个字节的地址
    operator PBYTE() const { return (PBYTE)m_pvFile;}

    //允许显式的关闭MMF,而不需要等待析构函数的执行
    VOID ForceClose();
};

//////////////////////////////////////////////////////////////////////////
BOOL CMMFSparse::Initialize(HANDLE hStream, DWORD dwStreamSizeMaxLow, DWORD dwStreamSizeMaxHigh){
    if (m_hFileMap != NULL)
        ForceClose();

    //初始化
    m_hFileMap = m_pvFile = NULL;

    BOOL bOk = TRUE; //假设是成功的

    if (hStream != NULL){
        if ((dwStreamSizeMaxLow == 0) && (dwStreamSizeMaxHigh ==0)){
            DebugBreak(); //非法的参数
        }

        CSparseStream::Initialize(hStream);
        bOk = MakeSparse();  //产生一个稀疏文件
        if (bOk){
            //创建一个内存文件映射对象
            m_hFileMap = ::CreateFileMapping(hStream, NULL, PAGE_READWRITE,
                                             dwStreamSizeMaxHigh,dwStreamSizeMaxLow,NULL);
            if (m_hFileMap != NULL){
                //将m_hFileMap映射到进程的地址空间,形成一个视图
                m_pvFile = ::MapViewOfFile(m_hFileMap, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0);            
            } else{
                //映射失败时
                CSparseStream::Initialize(NULL);
                ForceClose();
                bOk = FALSE;
            }
        }
    }
    return (bOk);
}

//////////////////////////////////////////////////////////////////////////
VOID CMMFSparse::ForceClose(){
    //清理
    if (m_pvFile != NULL){
        ::UnmapViewOfFile(m_pvFile); //撤消映射
        m_pvFile = NULL;
    }

    if (m_hFileMap != NULL){
        ::CloseHandle(m_hFileMap);
        m_hFileMap = NULL;
    }
}

//////////////////////////////////////////////////////////////////////////
TCHAR g_szPathname[MAX_PATH] = TEXT("\0");
HANDLE g_hStream = INVALID_HANDLE_VALUE;
CMMFSparse g_mmf;
#define STREAMSIZE   (1*1024*1024) //1MB (1024 KB)

//////////////////////////////////////////////////////////////////////////
void Dlg_ShowAllocatedRanges(HWND hwnd){
    //内存映射文件有实际的后备储存器的情况显示在“己分配范围”编辑框中
    DWORD dwNumEntries;
    FILE_ALLOCATED_RANGE_BUFFER* pfarb =
        g_mmf.QueryAllocateRanges(&dwNumEntries);
    if (dwNumEntries ==0){
        SetDlgItemText(hwnd, IDC_FILESTATUS, TEXT("文件中没有己分配的范围"));
    } else{
        TCHAR sz[4096] = { 0 };
        for (DWORD dwEntry = 0; dwEntry < dwNumEntries;dwEntry++)
            StringCchPrintf(_tcschr(sz, _T('\0')),
                            _countof(sz) - _tcslen(sz),
                            TEXT("偏移:0x%05X,长度:%u KB\r\n"),
                            //TEXT("偏移:%7.7u,长度:%7.7u\r\n"),
                            pfarb[dwEntry].FileOffset.LowPart,
                            pfarb[dwEntry].Length.LowPart/1024);
        SetDlgItemText(hwnd, IDC_FILESTATUS, sz);
    }

    g_mmf.FreeAllocateRanges(pfarb);
}

//////////////////////////////////////////////////////////////////////////
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam){
    chSETDLGICONS(hwnd, IDI_MMFSPARSE);

    //初始化对话框上的各控件
    EnableWindow(GetDlgItem(hwnd, IDC_OFFSET), FALSE);
    Edit_LimitText(GetDlgItem(hwnd, IDC_OFFSET), 4);
    SetDlgItemInt(hwnd, IDC_OFFSET, 1000, FALSE);

    EnableWindow(GetDlgItem(hwnd, IDC_BYTE), FALSE);
    Edit_LimitText(GetDlgItem(hwnd, IDC_BYTE),3);
    SetDlgItemInt(hwnd, IDC_BYTE, 5, FALSE);

    EnableWindow(GetDlgItem(hwnd, IDC_WRITEBYTE), FALSE);
    EnableWindow(GetDlgItem(hwnd, IDC_READBYTE), FALSE);
    EnableWindow(GetDlgItem(hwnd, IDC_FREEALLOCATEDREGIONS), FALSE);

    //将文件保存在一个可写的文件夹中
    GetCurrentDirectory(_countof(g_szPathname), g_szPathname);
    _tcscat_s(g_szPathname, _countof(g_szPathname), TEXT("\\MMFSparse"));

    //检查当前驱动器是否支持稀疏文件
    TCHAR szVolume[16];
    PTSTR pEndOfVolume = _tcschr(g_szPathname, _T('\\')); //查找驱动器号
    if (pEndOfVolume == NULL){
        chFAIL("无法在默认的文件夹中找到驱动器的卷标");
        DestroyWindow(hwnd);
        return TRUE;
    }

    _tcsncpy_s(szVolume, _countof(szVolume),
               g_szPathname,pEndOfVolume-g_szPathname +1); //含'\',形如:C:\
    
    if (!CSparseStream::DoesFileSystemSupportSparseStreams(szVolume)){
        chFAIL("默认的文件夹所在驱动器不支持稀疏文件!");
        DestroyWindow(hwnd);
        return TRUE;
    }

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtrl, UINT codeNotity){
    switch (id)
    {
    case IDCANCEL:
        EndDialog(hwnd, id);
        break;

    case IDC_CREATEMMF:
        {
            g_hStream = CreateFile(g_szPathname, GENERIC_READ | GENERIC_WRITE,
                                   0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
            if (g_hStream == INVALID_HANDLE_VALUE){
                chFAIL("创建文件失败!");
                return;
            }

            //创建一个1MB(1024KB)的MMF
            if (!g_mmf.Initialize(g_hStream,STREAMSIZE,0)){
                chFAIL("初始化稀疏内存映射文件失败!");
                CloseHandle(g_hStream);
                g_hStream = NULL;
                return;
            }

            //显示分配情况
            Dlg_ShowAllocatedRanges(hwnd);

            //启用或禁用相关控件
            EnableWindow(GetDlgItem(hwnd, IDC_CREATEMMF), FALSE);
            EnableWindow(GetDlgItem(hwnd, IDC_OFFSET),        TRUE);
            EnableWindow(GetDlgItem(hwnd, IDC_BYTE),        TRUE);
            EnableWindow(GetDlgItem(hwnd, IDC_WRITEBYTE),    TRUE);
            EnableWindow(GetDlgItem(hwnd, IDC_READBYTE),    TRUE);
            EnableWindow(GetDlgItem(hwnd, IDC_FREEALLOCATEDREGIONS), TRUE);

            //将焦点设置在“偏移”编辑框
            SetFocus(GetDlgItem(hwnd, IDC_OFFSET));
        }
        break;

    case IDC_READBYTE:
        {
            BOOL bTranslated;
            DWORD dwOffset = GetDlgItemInt(hwnd, IDC_OFFSET,
                                           &bTranslated,//转换是否成功
                                           FALSE);//无符号数
            if (bTranslated){
                SetDlgItemInt(hwnd, IDC_BYTE, g_mmf[dwOffset * 1024], FALSE);
                Dlg_ShowAllocatedRanges(hwnd);
            }
        }
        break;

    case IDC_WRITEBYTE:
        {
            BOOL bTranslated;
            DWORD dwOffset = GetDlgItemInt(hwnd, IDC_OFFSET,
                                           &bTranslated,//转换是否成功
                                           FALSE);//无符号数
            if (bTranslated){
                g_mmf[dwOffset * 1024] = (BYTE)
                       GetDlgItemInt(hwnd,IDC_BYTE,NULL,FALSE);
                Dlg_ShowAllocatedRanges(hwnd);
            }
        }
        break;

    case IDC_FREEALLOCATEDREGIONS:
        {
            //通常,析构函数会关闭内存映射文件。
            //但这里,我们是按“释放”按钮来强制关闭的,以便重置文件的一些区域为0
            g_mmf.ForceClose();

            //我们可以在上面调用ForceClose函数是因为当试图将一个己映射的
            //文件的部分区域置0时,会引起DeviceIoControl调用失败。
            g_mmf.DecommitPortionOfStream(0, STREAMSIZE);//文件所有字节都置0

            //要关闭文件句柄并重新打弄,以便将更改刷新稀疏文件的状态
            CloseHandle(g_hStream);

            //重新创建新文件
            g_hStream = CreateFile(g_szPathname, GENERIC_READ | GENERIC_WRITE,
                                   0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
            if (g_hStream == INVALID_HANDLE_VALUE){
                chFAIL("创建文件失败!");
                return;        
            }

            //重置为稀疏文件
            g_mmf.Initialize(g_hStream, STREAMSIZE, 0);

            //更新界面
            Dlg_ShowAllocatedRanges(hwnd);
        }
        break;
    }
}

//////////////////////////////////////////////////////////////////////////
INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
    switch (uMsg)
    {
        chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
        chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
    }
    return FALSE;
}
//////////////////////////////////////////////////////////////////////////
int WINAPI _tWinMain(HINSTANCE hInstExe, HINSTANCE, PTSTR pszCmdLine, int){
    DialogBox(hInstExe, MAKEINTRESOURCE(IDD_MMFSPARSE), NULL, Dlg_Proc);
    return 0;
}

//SparseStream.h

/************************************************************************
Module: SparseStream.h
Notices:Copyright(c) 2008 Jeffrey Richter & Christophe Nasarre
************************************************************************/
#include "../../CommonFiles/CmnHdr.h"
//#include <WinIoCtl.h> //For FILE_ALLOCATED_RANGE_BUFFER*
#pragma once
//////////////////////////////////////////////////////////////////////////

class CSparseStream{
public:
    //判断某个驱动器是否支持稀疏文件
    static BOOL DoesFileSystemSupportSparseStreams(PCTSTR pszVolume);
    //判断一个文件是否是稀疏文件(静态方法)
    static BOOL DoesFileContainAnySparseStreams(PCTSTR pszPathname);

public:
    CSparseStream(HANDLE hStream = INVALID_HANDLE_VALUE){
        Initialize(hStream);
    }

    virtual ~CSparseStream(){}

    void Initialize(HANDLE hStream = INVALID_HANDLE_VALUE){
        m_hStream = hStream;
    }
public:
    BOOL IsStreamSparse() const; //是否是稀疏文件(非静态方法)
    BOOL MakeSparse(); //产生稀疏文件

    //给稀疏文件指定范围的内容填0
    BOOL DecommitPortionOfStream(__int64 qwFileOffsetStart, __int64 qwFileOffsetEnd);

    //查找稀疏文件中非零数据的范围
    FILE_ALLOCATED_RANGE_BUFFER* QueryAllocateRanges(PDWORD pdwNumEntries);

    //释放QueryAllocateRanges分配到的内存空间
    BOOL FreeAllocateRanges(FILE_ALLOCATED_RANGE_BUFFER* pfarb);

public:
    operator HANDLE() const{ return (m_hStream);}
private:
    HANDLE m_hStream;

private:
    static BOOL AreFlagsSet(DWORD fdwFlagBits, DWORD fFlagsToCheck){
        return ((fdwFlagBits & fFlagsToCheck) == fFlagsToCheck);
    }
};

//////////////////////////////////////////////////////////////////////////
inline BOOL CSparseStream::DoesFileSystemSupportSparseStreams(PCTSTR pszVolume){
    DWORD dwFileSystemFlags = 0;
    BOOL bOk = GetVolumeInformation(pszVolume, NULL, 0, NULL, NULL,
                                    &dwFileSystemFlags, NULL, 0);
    bOk = bOk&& AreFlagsSet(dwFileSystemFlags, FILE_SUPPORTS_SPARSE_FILES);
    return bOk;
}

//////////////////////////////////////////////////////////////////////////
inline BOOL CSparseStream::DoesFileContainAnySparseStreams(PCTSTR pszPathname){
    DWORD dw = GetFileAttributes(pszPathname);
    return ((dw == 0xFFFFFFFF) ? 
             FALSE:
             AreFlagsSet(dw,FILE_ATTRIBUTE_SPARSE_FILE));
}

//////////////////////////////////////////////////////////////////////////
inline BOOL CSparseStream::IsStreamSparse() const{
    BY_HANDLE_FILE_INFORMATION bhfi;
    GetFileInformationByHandle(m_hStream, &bhfi);
    
    return (AreFlagsSet(bhfi.dwFileAttributes, FILE_ATTRIBUTE_SPARSE_FILE));
}

//////////////////////////////////////////////////////////////////////////
inline BOOL CSparseStream::MakeSparse(){
    DWORD dw;
    return (DeviceIoControl(m_hStream, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dw, NULL));
}

//////////////////////////////////////////////////////////////////////////
//给文件指定范围的内容填0.如果文件是稀疏文件,NTFS会释放文件,并不会扩大文件的实际大小
inline BOOL CSparseStream::DecommitPortionOfStream(__int64 qwFileOffsetStart, __int64 qwFileOffsetEnd){
    //注意:如果文件尚未被映射时,该函数将不能正常工作
    DWORD dw;
    FILE_ZERO_DATA_INFORMATION fzdi;
    fzdi.FileOffset.QuadPart = qwFileOffsetStart;
    fzdi.BeyondFinalZero.QuadPart = qwFileOffsetEnd + 1;
    return (DeviceIoControl(
        m_hStream, //文件句柄
        FSCTL_SET_ZERO_DATA,//控制码
        (PVOID)&fzdi, //input buffer,指明了文件要设置为0的范围
        sizeof(fzdi), //缓冲区大小
        NULL, //lpOutBuffer
        0,    //nOutBufferSize
        &dw, //number of bytes returned
        NULL));
}

//////////////////////////////////////////////////////////////////////////
//查找稀疏文件中包含非零数据的范围
FILE_ALLOCATED_RANGE_BUFFER* CSparseStream::QueryAllocateRanges(PDWORD pdwNumEntries){
    FILE_ALLOCATED_RANGE_BUFFER farb;
    farb.FileOffset.QuadPart = 0;
    farb.Length.LowPart = GetFileSize(m_hStream, (PDWORD)&farb.Length.HighPart);

    //试图收集数据之前,我们没有办法切确地知道内存块的大小,这里我们选择100*sizeof(farb)
    DWORD cb = 100 * sizeof(farb);
    FILE_ALLOCATED_RANGE_BUFFER* pfarb = (FILE_ALLOCATED_RANGE_BUFFER*)
        HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
    
    DeviceIoControl(m_hStream, FSCTL_QUERY_ALLOCATED_RANGES,
                    &farb,sizeof(farb),//输入缓冲区
                    pfarb,cb,&cb, //输出缓冲区
                    NULL);
    *pdwNumEntries = cb / sizeof(*pfarb);
    return (pfarb);
}

//////////////////////////////////////////////////////////////////////////
inline BOOL CSparseStream::FreeAllocateRanges(FILE_ALLOCATED_RANGE_BUFFER* pfarb){
    return (HeapFree(GetProcessHeap(), 0, pfarb));
}

/////////////////////////////文件结束/////////////////////////////////////

//resource.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 17_MMFSparse.rc 使用
//
#define IDD_MMFSPARSE                   1
#define IDC_CREATEMMF                   101
#define IDI_MMFSPARSE                   102
#define IDC_OFFSET                      103
#define IDC_WRITEBYTE                   105
#define IDC_READBYTE                    106
#define IDC_BYTE                        109
#define IDC_FILESTATUS                  1000
#define IDC_FREEALLOCATEDREGIONS        1002

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        103
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

//MMFSparse.rc

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// 中文(简体,中国) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""winres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_MMFSPARSE           ICON                    "MMFSparse.ico"

/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_MMFSPARSE DIALOGEX 15, 24, 188, 192
STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "MMF Sparse"
FONT 10, "宋体", 400, 0, 0x0
BEGIN
    DEFPUSHBUTTON   "创建一个1M(1024KB)的稀疏内存映射文件对象",IDC_CREATEMMF,10,3,168,14,WS_GROUP
    LTEXT           "偏移(0 - 1023KB):",IDC_STATIC,10,23,68,8
    EDITTEXT        IDC_OFFSET,81,21,44,12
    PUSHBUTTON      "读取字节",IDC_READBYTE,132,19,46,14
    LTEXT           "字节(0-255):",IDC_STATIC,11,38,47,8
    EDITTEXT        IDC_BYTE,81,36,44,12,ES_UPPERCASE | ES_NUMBER
    PUSHBUTTON      "写入字节",IDC_WRITEBYTE,132,35,46,14
    PUSHBUTTON      "释放所有己分配的区域",IDC_FREEALLOCATEDREGIONS,80,51,98,14
    LTEXT           "分配范围:",IDC_STATIC,9,63,59,8
    EDITTEXT        IDC_FILESTATUS,9,72,170,116,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
    IDD_MMFSPARSE, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 184
        TOPMARGIN, 1
        BOTTOMMARGIN, 190
    END
END
#endif    // APSTUDIO_INVOKED

#endif    // 中文(简体,中国) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

17.8.3 内存映射文件的其他问题

(1)CreateFileMapping中fdwProtect参数的讨论

  ①SEC_COMMIT:只有当以页交换文件为后备存储器时才有起作用,用于给区域调拨物理存储器。不指定该标志时,默认也是以SEC_COMMIT创建内存映射文件的。(SEC,Section的缩写)。

  ②SEC_RESERVE:也是以页交换文件为后备存储器,但系统不会从页交换文件中调拨物理存储器,只返回文件映射对象的句柄。

(2)利用SEC_RESERVE进行部分区域的调拨

  ①默认下CreateFileMapping映射文件时,会传入SEC_COMMIT标志,所以MapViewOfFile会预订一块地址空间区域,并给区域(大小由该函数的dwNumberOfBytesToMap参数指定)全部调拨物理存储器,这有点浪费。我们可以在CreateFileMapping创建时传入SEC_RESERVE,用于告诉MapViewOfFile只预订这个区域,而不调拨物理存储器!

  ②区域的部分调拨的具体步骤:

    A、CreateFileMapping时传入SEC_RESERVE。

    B、创建视图:pvAddress = MapViewOfFile,这时会得到一个区域,但只是预订而不会给区域调拨物理存储器。

    C、调用VirtualAlloc给区域调拨物理存储器,传上面的pvAddress传入该函数

    D、这里可以像一般的内存映射文件一样的使用了。

  ③注意事项:

    A、通过SEC_RESERVE标志得到的内存映射文件,不能用VirtualFree来撤消调拨的物理存储器,仍然要用UnmapViewOfFile。

    B、SEC_RESERVE和SEC_COMMIT标志只能用在以“页交换”文件为后备存储器的内存映射文件。