Windows内存体系(5)-- 内存映射文件技术的使用
程序员文章站
2022-04-03 08:04:49
...
前面的《Windows内存体系(3) – 内存映射文件》文章,对内存映射文件技术的原理进行了介绍,本篇文章着重介绍该技术的使用场景。
一、内存映射文件技术介绍
常用的有Win32 API的CreateFile()
、WriteFile()
、ReadFile()
和MFC提供的CFile
类都可以实现文件的读写操作。一般来说,以上这些函数可以满足大多数场合的要求,但是对于某些特殊应用领域所需要的动辄几十GB、几百GB、乃至几TB的海量存储,再以平常的文件处理方法进行处理显然是行不通的(效率低下,而且内存没那么大)。目前,对于这种大文件的操作一般是以内存映射文件的方式来加以处理的。
内存映射文件也是Windows的一种内存管理方法,提供了一个统一的内存管理特征,使应用程序可以通过内存指针对磁盘上的文件进行访问。通过文件映射将磁盘文件内容(全部或者部分)与进程虚拟地址空间的某个区域建立映射关联,可以直接对被映射的文件进行访问,而不必执行文件I/O操作也无需对文件内容进行缓冲处理。内存文件映射的这种特性是非常适合于用来管理大尺寸文件的。
二、大文件读写实例
通过C++调用系统API实现文件映射的步骤大致如下:
示例
本示例先在D:\
生成一个大小为1GB的BigFile.data
文件,然后使用内存映射技术将该文件内全部填充字符A,随后读取其中的第20000~20100字节
,并将这些字节修改为字符B,然后再次读取已验证是否修改成功。
#include <windows.h>
void Test() {
HANDLE file_ = CreateFile(TEXT("D:\\BigFile.data"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (file_ == INVALID_HANDLE_VALUE) {
printf("CreateFile failed, GLE:%d\n", GetLastError());
return;
}
LARGE_INTEGER filesize;
filesize.QuadPart = 1024 * 1024 * 1024; // 1GB
HANDLE mapping_ = CreateFileMapping(file_, NULL, PAGE_READWRITE, filesize.HighPart, filesize.LowPart, NULL);
if (mapping_ == NULL) {
printf("CreateFileMapping failed, GLE:%d\n", GetLastError());
return;
}
LARGE_INTEGER offset;
offset.QuadPart = 0;
LPVOID mapping_addr = MapViewOfFile(mapping_, FILE_MAP_WRITE | FILE_MAP_READ, offset.HighPart, offset.LowPart, 0);
if (mapping_addr == NULL) {
printf("MapViewOfFile failed, GLE:%d\n", GetLastError());
return;
}
// 向文件中填充1GB的字符'A'
//
char buf[1024];
for (int i = 0; i < 1024; i++) {
buf[i] = 'A';
}
// 每次填充1024字节,填充1024*1024次
for (long l = 0; l < 1024 * 1024; l++) {
memcpy((LPVOID)((long)mapping_addr + l * 1024), buf, 1024);
}
// 填充完毕
// 读取第20000~20100字节,共100字节
//
char read_content[101] = { 0 };
memcpy(read_content, (LPVOID)((long)mapping_addr + 20000), 100);
printf("%s\n", read_content);
// 将第20000~20100字节,共100字节全部修改为字符'B'
//
char write_content[100];
for (int i = 0; i < 100; i++) {
write_content[i] = 'B';
}
memcpy((LPVOID)((long)mapping_addr + 20000), write_content, 100);
// 再次读取第20000~20100字节,共100字节,验证修改是成功
//
memcpy(read_content, (LPVOID)((long)mapping_addr + 20000), 100);
printf("%s\n", read_content);
UnmapViewOfFile(mapping_addr);
CloseHandle(mapping_);
CloseHandle(file_);
return;
}
int main()
{
Test();
return 0;
}
上一篇: API & Java.lang