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)的更多相关文章

  1. 《windows核心编程》 17章 内存映射文件

    内存映射文件主要用于以下三种情况: 系统使用内存映射文件载入并运行exe和dll,这大量节省了页交换文件的空间以及应用程序的启动时间 开发人员可以使用内存映射文件来访问磁盘上的数据文件.这使得我们可以 ...

  2. Windows核心编程 第十七章 -内存映射文件(上)

    第1 7章 内存映射文件 对文件进行操作几乎是所有应用程序都必须进行的,并且这常常是人们争论的一个问题.应用程序究竟是应该打开文件,读取文件并关闭文件,还是打开文件,然后使用一种缓冲算法,从文件的各个 ...

  3. Linux文件空洞与稀疏文件 转

      1.Linux文件空洞与稀疏文件 2.文件系统数据存储 3.文件系统调试   文件空洞   在UNIX文件操作中,文件位移量可以大于文件的当前长度在这种情况下,对该文件的下一次写将延长该文件,并在 ...

  4. Windows核心编程 第十七章 -内存映射文件(下)

    17.3 使用内存映射文件 若要使用内存映射文件,必须执行下列操作步骤: 1) 创建或打开一个文件内核对象,该对象用于标识磁盘上你想用作内存映射文件的文件. 2) 创建一个文件映射内核对象,告诉系统该 ...

  5. LDD3 第15章 内存映射和DMA

    本章内容分为三个部分: 第一部分讲述了mmap系统调用的实现过程.将设备内存直接映射到用户进程的地址空间,尽管不是所有设备都需要,但是能显著的提高设备性能. 如何跨越边界直接访问用户空间的内存页,一些 ...

  6. 使用Java内存映射(Memory-Mapped Files)处理大文件

    >>NIO中的内存映射 (1)什么是内存映射文件内存映射文件,是由一个文件到一块内存的映射,可以理解为将一个文件映射到进程地址,然后可以通过操作内存来访问文件数据.说白了就是使用虚拟内存将 ...

  7. 《Linux Device Drivers》第十五章 内存映射和DMA——note

    简单介绍 很多类型的驱动程序编程都须要了解一些虚拟内存子系统怎样工作的知识 当遇到更为复杂.性能要求更为苛刻的子系统时,本章所讨论的内容迟早都要用到 本章的内容分成三个部分 讲述mmap系统调用的实现 ...

  8. Java内存映射,上G大文件轻松处理

    内存映射文件(Memory-mapped File),指的是将一段虚拟内存逐字节映射于一个文件,使得应用程序处理文件如同访问主内存(但在真正使用到这些数据前却不会消耗物理内存,也不会有读写磁盘的操作) ...

  9. python文件操作_对文件进行复制拷贝_代码实现

    要求: 1,对已经存在的文件进行复制操作 2,复制后的文件在文件名后面加上[复件] 3,文件比较大如何优化处理 #-*- coding: UTF-8 -*- #这是python 2 下面写的,用的ra ...

随机推荐

  1. [C#]多线程下载

    发现电脑里以前编写的下载程序... 做个记录,那时做的挺匆忙的,没用委托,通过公开出窗体来修改下载进度,做的比较乱... ==!! 程序具体功能(流程): 1.检测系统托盘图标内的进程名是否符合要求 ...

  2. ArcMap中的名称冲突问题

    这是一个非常有趣的问题. 现在我一个点层叫"汶川73",有一个面层也叫"汶川73",使用空间连接工具来计算每个面中被落入有多少个点.但不管怎么算,结果都只能生成 ...

  3. Uploading Files in SharePoint 2013 using CSOM and REST

    http://www.shillier.com/archive/2013/03/26/uploading-files-in-sharepoint-2013-using-csom-and-rest.as ...

  4. 案例分享:电信行业零售业务CRM架构

    最近跟一个客户讨论销售领域的移动化需求,谈到了他们的零售业务系统的整体框架,觉得很有分享的必要. 这次聊到的客户是电信行业的巨头,说的是他们的零售业务.电信公司么,卖出去的无非是设备和服务.大体的业务 ...

  5. onWindowFocusChanged

    这个onWindowFocusChanged指的是这个Activity得到或者失去焦点的时候 就会call. 也就是说 如果你想要做一个Activity一加载完毕,就触发什么的话 完全可以用这个!!! ...

  6. Android-ListView类

    ListView组件在应用程序中可以说是不可或缺的一部分,ListView主要是显示列表数据,同时可以滚动查看,这篇博客主要是对ListView的基本用法进行说明,后面会依次对ListView点击动态 ...

  7. 第一次开发PHP网页Hello PHP

    打开安装好的XAMPP的三个服务: 然后打开phpStorm,在Open选项选择文件目录(最后一个目录是htdocs)打开: 3.有时候可能无法修改php文件,会弹出一些提示窗口.那么就打开Finde ...

  8. linux64位操作系统装32位jdk解决方法

    /opt/tomcat/tomcat7.0/bin/catalina.sh: /usr/local/java/jdk1.7.0_79/bin/java: /lib/ld-linux.so.2: bad ...

  9. nginx安装过程,报错处理:make[1]: *** [objs/addon/src/bson.o] Error 1

    nginx安装过程中,经常会有各种错误: 具体安装步骤这里不做说明,网上一搜大把: 主要分析安装过程中遇到的问题 在make编译的时候,若报如下错误: cc1: warnings being trea ...

  10. win7 64位安装oracle10g出现未知错误,程序异常终止解决方法

    修改Oracle 10G\database\stage\prereq\db\refhost.xml 在 </SYSTEM> <CERTIFIED_SYSTEMS>后面添加 &l ...