文档库 最新最全的文档下载
当前位置:文档库 › 使用内存映射文件处理大文件应用示例

使用内存映射文件处理大文件应用示例

下面结合一个具体的实例来进一步讲述内存映射文件的使用方法。该实例从端口接收数据,并实时将其存放于磁盘,由于数据量大(几十GB),在此选用内存映射文件进行处理。下面给出的是位于工作线程MainProc中的部分主要代码,该线程自程序运行时启动,当端口有数据到达时将会发出事件hEvent[0],WaitForMultipleObjects()函数等待到该事件发生后将接收到的数据保存到磁盘,如果终止接收将发出事件hEvent[1],事件处理过程将负责完成资源的释放和文件的关闭等工作。下面给出此线程处理函数的具体实现过程:

……
// 创建文件内核对象,其句柄保存于hFile
HANDLE hFile = CreateFile( "Recv1.zip ",
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL);

// 创建文件映射内核对象,句柄保存于hFileMapping
HANDLE hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READWRITE,
0, 0x4000000, NULL);
// 释放文件内核对象
CloseHandle(hFile);

// 设定大小、偏移量等参数
__int64 qwFileSize = 0x4000000;
__int64 qwFileOffset = 0;
__int64 T = 600 * sinf.dwAllocationGranularity;
DWORD dwBytesInBlock = 1000 * sinf.dwAllocationGranularity;

// 将文件数据映射到进程的地址空间
PBYTE pbFile = (PBYTE)MapViewOfFile(hFileMapping,
FILE_MAP_ALL_ACCESS,
(DWORD)(qwFileOffset> > 32), (DWORD)(qwFileOffset&0xFFFFFFFF), dwBytesInBlock);
while(bLoop)
{
// 捕获事件hEvent[0]和事件hEvent[1]
DWORD ret = WaitForMultipleObjects(2, hEvent, FALSE, INFINITE);
ret -= WAIT_OBJECT_0;
switch (ret)
{
// 接收数据事件触发
case 0:
// 从端口接收数据并保存到内存映射文件
nReadLen=syio_Read(port[1], pbFile + qwFileOffset, QueueLen);
qwFileOffset += nReadLen;

// 当数据写满60%时,为防数据溢出,需要在其后开辟一新的映射视图
if (qwFileOffset > T)
{
T = qwFileOffset + 600 * sinf.dwAllocationGranularity;
UnmapViewOfFile(pbFile);
pbFile = (PBYTE)MapViewOfFile(hFileMapping,
FILE_MAP_ALL_ACCESS,
(DWORD)(qwFileOffset> > 32), (DWORD)(qwFileOffset&0xFFFFFFFF), dwBytesInBlock);
}
break;

// 终止事件触发
case 1:
bLoop = FALSE;

// 从进程的地址空间撤消文件数据映像
UnmapViewOfFile(pbFile);

// 关闭文件映射对象
CloseHandle(hFileMapping);
break;
}
}


在终止事件触发处理过程中如果只简单的执行UnmapViewOfFile()和CloseHandle()函数将无法正确标识文件的实际大小,即如果开辟的内存映射文件为30GB,而接收的数据只有14GB,那么上述程序执行完后,保存的文件长度仍是30GB。也就是说,在处理完成后还要再次通

过内存映射文件的形式将文件恢复到实际大小,下面是实现此要求的主要代码:

// 创建另外一个文件内核对象
hFile2 = CreateFile( "Recv.zip ",
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL);

// 以实际数据长度创建另外一个文件映射内核对象
hFileMapping2 = CreateFileMapping(hFile2,
NULL,
PAGE_READWRITE,
0,
(DWORD)(qwFileOffset&0xFFFFFFFF),
NULL);

// 关闭文件内核对象
CloseHandle(hFile2);

// 将文件数据映射到进程的地址空间
pbFile2 = (PBYTE)MapViewOfFile(hFileMapping2,
FILE_MAP_ALL_ACCESS,
0, 0, qwFileOffset);

// 将数据从原来的内存映射文件复制到此内存映射文件
memcpy(pbFile2, pbFile, qwFileOffset);

file://从进程的地址空间撤消文件数据映像
UnmapViewOfFile(pbFile);
UnmapViewOfFile(pbFile2);

// 关闭文件映射对象
CloseHandle(hFileMapping);
CloseHandle(hFileMapping2);

// 删除临时文件
DeleteFile( "Recv1.zip ");

结论

经实际测试,内存映射文件在处理大数据量文件时表现出了良好的性能,比通常使用CFile类和ReadFile()和WriteFile()等函数的文件处理方式具有明显的优势。本文所述代码在Windows 98下由Microsoft Visual C++ 6.0编译通过。

相关文档
相关文档 最新文档