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

2023-06-14,,

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 = ,
DWORD dwStreamSizeMaxHigh = ){
Initialize(hStream, dwStreamSizeMaxLow, dwStreamSizeMaxHigh);
} //关闭Sparse MMF
virtual ~CMMFSparse(){ ForceClose(); } //创建一个以稀疏文件为后备存储器的MMF对象,并映射到进程的地址空间
BOOL Initialize(HANDLE hStream = NULL, DWORD dwStreamSizeMaxLow = ,
DWORD dwStreamSizeMaxHigh = ); //将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 == ) && (dwStreamSizeMaxHigh ==)){
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, , , );
} 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 ==){
SetDlgItemText(hwnd, IDC_FILESTATUS, TEXT("文件中没有己分配的范围"));
} else{
TCHAR sz[] = { };
for (DWORD dwEntry = ; 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/);
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), );
SetDlgItemInt(hwnd, IDC_OFFSET, , FALSE); EnableWindow(GetDlgItem(hwnd, IDC_BYTE), FALSE);
Edit_LimitText(GetDlgItem(hwnd, IDC_BYTE),);
SetDlgItemInt(hwnd, IDC_BYTE, , 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[];
PTSTR pEndOfVolume = _tcschr(g_szPathname, _T('\\')); //查找驱动器号
if (pEndOfVolume == NULL){
chFAIL("无法在默认的文件夹中找到驱动器的卷标");
DestroyWindow(hwnd);
return TRUE;
} _tcsncpy_s(szVolume, _countof(szVolume),
g_szPathname,pEndOfVolume-g_szPathname +); //含'\',形如: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,
, 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,)){
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 * ], FALSE);
Dlg_ShowAllocatedRanges(hwnd);
}
}
break; case IDC_WRITEBYTE:
{
BOOL bTranslated;
DWORD dwOffset = GetDlgItemInt(hwnd, IDC_OFFSET,
&bTranslated,//转换是否成功
FALSE);//无符号数
if (bTranslated){
g_mmf[dwOffset * ] = (BYTE)
GetDlgItemInt(hwnd,IDC_BYTE,NULL,FALSE);
Dlg_ShowAllocatedRanges(hwnd);
}
}
break; case IDC_FREEALLOCATEDREGIONS:
{
//通常,析构函数会关闭内存映射文件。
//但这里,我们是按“释放”按钮来强制关闭的,以便重置文件的一些区域为0
g_mmf.ForceClose(); //我们可以在上面调用ForceClose函数是因为当试图将一个己映射的
//文件的部分区域置0时,会引起DeviceIoControl调用失败。
g_mmf.DecommitPortionOfStream(, STREAMSIZE);//文件所有字节都置0 //要关闭文件句柄并重新打弄,以便将更改刷新稀疏文件的状态
CloseHandle(g_hStream); //重新创建新文件
g_hStream = CreateFile(g_szPathname, GENERIC_READ | GENERIC_WRITE,
, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (g_hStream == INVALID_HANDLE_VALUE){
chFAIL("创建文件失败!");
return;
} //重置为稀疏文件
g_mmf.Initialize(g_hStream, STREAMSIZE, ); //更新界面
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 ;
}

//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 = ;
BOOL bOk = GetVolumeInformation(pszVolume, NULL, , NULL, NULL,
&dwFileSystemFlags, NULL, );
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, , NULL, , &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 + ;
return (DeviceIoControl(
m_hStream, //文件句柄
FSCTL_SET_ZERO_DATA,//控制码
(PVOID)&fzdi, //input buffer,指明了文件要设置为0的范围
sizeof(fzdi), //缓冲区大小
NULL, //lpOutBuffer
, //nOutBufferSize
&dw, //number of bytes returned
NULL));
} //////////////////////////////////////////////////////////////////////////
//查找稀疏文件中包含非零数据的范围
FILE_ALLOCATED_RANGE_BUFFER* CSparseStream::QueryAllocateRanges(PDWORD pdwNumEntries){
FILE_ALLOCATED_RANGE_BUFFER farb;
farb.FileOffset.QuadPart = ;
farb.Length.LowPart = GetFileSize(m_hStream, (PDWORD)&farb.Length.HighPart); //试图收集数据之前,我们没有办法切确地知道内存块的大小,这里我们选择100*sizeof(farb)
DWORD cb = * 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(), , 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
// TEXTINCLUDE
BEGIN
"resource.h\0"
END TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END 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 , , ,
STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "MMF Sparse"
FONT , "宋体", , , 0x0
BEGIN
DEFPUSHBUTTON "创建一个1M(1024KB)的稀疏内存映射文件对象",IDC_CREATEMMF,,,,,WS_GROUP
LTEXT "偏移(0 - 1023KB):",IDC_STATIC,,,,
EDITTEXT IDC_OFFSET,,,,
PUSHBUTTON "读取字节",IDC_READBYTE,,,,
LTEXT "字节(0-255):",IDC_STATIC,,,,
EDITTEXT IDC_BYTE,,,,,ES_UPPERCASE | ES_NUMBER
PUSHBUTTON "写入字节",IDC_WRITEBYTE,,,,
PUSHBUTTON "释放所有己分配的区域",IDC_FREEALLOCATEDREGIONS,,,,
LTEXT "分配范围:",IDC_STATIC,,,,
EDITTEXT IDC_FILESTATUS,,,,,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL
END /////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
// #ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_MMFSPARSE, DIALOG
BEGIN
LEFTMARGIN,
RIGHTMARGIN,
TOPMARGIN,
BOTTOMMARGIN,
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标志只能用在以“页交换”文件为后备存储器的内存映射文件。

第17章 内存映射文件(3)_稀疏文件(Sparse File)的相关教程结束。

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

下载本文的Word格式文档,以方便收藏与打印。