c - 在 Windows 上将文件映射到 C 中的虚拟内存
问题描述
在 POSIX 系统上,我可以使用 mmap 函数比 getline、getc 等更快地读取文件的内容。这在我正在开发的程序中很重要,因为它需要将非常大的文件读入内存;使用 getline 迭代收集行的成本太高。可移植性也是我的软件的要求,所以如果我使用 mmap,我需要找到一种使用 WinApi 来存储映射文件的方法,因为我宁愿不通过 cygwin/msys 编译。通过粗略的搜索,我发现了这篇MSDN 文章,它非常简要地描述了一种将文件映射到内存中的方法,但是,从浏览文档中我无法确定如何实际实现它,而且我一直在寻找示例代码片段,就像 POSIX mmap 的代码片段一样。
如何使用 WinApi 的内存映射选项将文件读入 char*?
解决方案
如何使用 WinApi 的内存映射选项将文件读入 char*?
在 Windows 下,当你在内存中映射一个文件时,你会得到一个指向文件第一个字节被映射的内存位置的指针。您可以将该指针转换为您喜欢的任何数据类型,包括 char*。
换句话说,由 Windows 决定映射数据在内存中的位置。您不能提供 char* 并期望 Windows 会在那里加载数据。
这意味着如果您已经有一个 char* 并且想要该 char* 指向的位置中的文件中的数据,那么您必须复制它。在性能方面不是一个好主意。
这是一个通过将文件映射到内存然后显示所有 ASCII 字符来转储文本文件的简单程序。使用 MSVC2019 测试。
#include <stdio.h>
#include <Windows.h>
int main(int argc, char *argv[])
{
TCHAR *lpFileName = TEXT("hello.txt");
HANDLE hFile;
HANDLE hMap;
LPVOID lpBasePtr;
LARGE_INTEGER liFileSize;
hFile = CreateFile(lpFileName,
GENERIC_READ, // dwDesiredAccess
0, // dwShareMode
NULL, // lpSecurityAttributes
OPEN_EXISTING, // dwCreationDisposition
FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
0); // hTemplateFile
if (hFile == INVALID_HANDLE_VALUE) {
fprintf(stderr, "CreateFile failed with error %d\n", GetLastError());
return 1;
}
if (!GetFileSizeEx(hFile, &liFileSize)) {
fprintf(stderr, "GetFileSize failed with error %d\n", GetLastError());
CloseHandle(hFile);
return 1;
}
if (liFileSize.QuadPart == 0) {
fprintf(stderr, "File is empty\n");
CloseHandle(hFile);
return 1;
}
hMap = CreateFileMapping(
hFile,
NULL, // Mapping attributes
PAGE_READONLY, // Protection flags
0, // MaximumSizeHigh
0, // MaximumSizeLow
NULL); // Name
if (hMap == 0) {
fprintf(stderr, "CreateFileMapping failed with error %d\n", GetLastError());
CloseHandle(hFile);
return 1;
}
lpBasePtr = MapViewOfFile(
hMap,
FILE_MAP_READ, // dwDesiredAccess
0, // dwFileOffsetHigh
0, // dwFileOffsetLow
0); // dwNumberOfBytesToMap
if (lpBasePtr == NULL) {
fprintf(stderr, "MapViewOfFile failed with error %d\n", GetLastError());
CloseHandle(hMap);
CloseHandle(hFile);
return 1;
}
// Display file content as ASCII charaters
char *ptr = (char *)lpBasePtr;
LONGLONG i = liFileSize.QuadPart;
while (i-- > 0) {
fputc(*ptr++, stdout);
}
UnmapViewOfFile(lpBasePtr);
CloseHandle(hMap);
CloseHandle(hFile);
printf("\nDone\n");
}
推荐阅读
- java - 在未排序的数组中查找唯一元素
- c - rand() / RAND_MAX 是否返回 [0, 1) 或 [0,1]?
- amazon-web-services - 创建 CA 证书时 AWS 中的 ValidationException
- javascript - 在 Doc Google 表格中编写 Google 合并单元格脚本
- reactjs - Normalizr - 我将在哪里修改实体?
- php - 无法从多个数组中获取完整的名称列表
- android - 无法自动读取OREO中的短信
- sparql - SPARQL 查询以检索以特定 URI 开头的所有主题
- python - 如何让 unicode 源代码影响整个字符串而不仅仅是第一个字符?
- ios - 从一个 VC 的按钮呈现给另一个 VC 使 SWrevealviewcontroller 发现为零